diff --git a/.github/workflows/bazel.yml b/.github/workflows/bazel.yml index 747c9210d8..125d3de5e9 100644 --- a/.github/workflows/bazel.yml +++ b/.github/workflows/bazel.yml @@ -235,6 +235,17 @@ jobs: rbe: false runner: ubuntu-24.04-arm targets: //compile/test:cross_compile_x86_64_no_unwind_test + # Live counterpart of //pgp/test:audit_test - re-runs the audit + # against a real `bazel aquery` of //pgp/test's example targets + # rather than captured JSON (see bazel/pgp/README.md#auditing). + - name: pgp-live-audit + action: run + bazel_args: --config=ci + bazel_mode: bzlmod + privileged: false + rbe: false + runner: ubuntu-24.04 + targets: //pgp/test:live_audit status: runs-on: ubuntu-24.04 diff --git a/actions/bazel/cache/resolve/action.yml b/actions/bazel/cache/resolve/action.yml index 49f694830c..ea7846d20f 100644 --- a/actions/bazel/cache/resolve/action.yml +++ b/actions/bazel/cache/resolve/action.yml @@ -1,4 +1,4 @@ -#name: bazel/cache/resolve +# name: bazel/cache/resolve description: | Parse MODULE.bazel.lock into a {cache-key: path} map for caches/restore+save diff --git a/bazel/MODULE.bazel b/bazel/MODULE.bazel index 399bbd6493..fc6586d614 100644 --- a/bazel/MODULE.bazel +++ b/bazel/MODULE.bazel @@ -109,6 +109,17 @@ use_repo(wee8_prebuilt_ext, "wee8_prebuilt_x86_64", "wee8_prebuilt_x86_64_libstd # libcxx_libs_ext.setup() # use_repo(libcxx_libs_ext, "libcxx_libs_aarch64", "libcxx_libs_x86_64") +# Setup the OpenPGP signer (`sq`) toolchain - example for downstream consumers +# Uncomment to use in your MODULE.bazel, supplying sha256s you have verified: +# pgp_ext = use_extension("@envoy_toolshed//pgp:extensions.bzl", "pgp_extension") +# pgp_ext.setup( +# sha256s = { +# "linux_x86_64": "", +# }, +# ) +# use_repo(pgp_ext, "sq_linux_x86_64") +# register_toolchains("@sq_linux_x86_64//:toolchain") + # Setup grcov for code coverage - example for downstream consumers # Uncomment to use in your MODULE.bazel: # grcov_ext = use_extension("@envoy_toolshed//coverage/grcov:extensions.bzl", "grcov_extension") @@ -177,6 +188,10 @@ use_repo(llvm, "llvm_toolchain") register_toolchains("@llvm_toolchain//:all", dev_dependency = True) +# Stub OpenPGP signer used by //pgp/test analysis tests. Real signing requires +# a `sq` toolchain, see //pgp:extensions.bzl. +register_toolchains("//pgp/test:stub_toolchain", dev_dependency = True) + libcxx_ext = use_extension("//compile:extensions.bzl", "libcxx_extension", dev_dependency = True) use_repo(libcxx_ext, "llvm_libcxx_aarch64", "llvm_libcxx_x86_64") diff --git a/bazel/MODULE.bazel.lock b/bazel/MODULE.bazel.lock index 13d985e422..080c315089 100644 --- a/bazel/MODULE.bazel.lock +++ b/bazel/MODULE.bazel.lock @@ -1,5 +1,5 @@ { - "lockFileVersion": 24, + "lockFileVersion": 28, "registryFileHashes": { "https://bcr.bazel.build/bazel_registry.json": "8a28e4aff06ee60aed2a8c281907fb8bcbf3b753c91fb5a5c57da3215d5b3497", "https://bcr.bazel.build/modules/abseil-cpp/20210324.2/MODULE.bazel": "7cd0312e064fde87c8d1cd79ba06c876bd23630c83466e9500321be55c96ace2", @@ -21,8 +21,10 @@ "https://bcr.bazel.build/modules/abseil-py/2.1.0/source.json": "0e8fc4f088ce07099c1cd6594c20c7ddbb48b4b3c0849b7d94ba94be88ff042b", "https://bcr.bazel.build/modules/apple_support/1.11.1/MODULE.bazel": "1843d7cd8a58369a444fc6000e7304425fba600ff641592161d9f15b179fb896", "https://bcr.bazel.build/modules/apple_support/1.15.1/MODULE.bazel": "a0556fefca0b1bb2de8567b8827518f94db6a6e7e7d632b4c48dc5f865bc7c85", - "https://bcr.bazel.build/modules/apple_support/1.23.1/MODULE.bazel": "53763fed456a968cf919b3240427cf3a9d5481ec5466abc9d5dc51bc70087442", + "https://bcr.bazel.build/modules/apple_support/1.21.0/MODULE.bazel": "ac1824ed5edf17dee2fdd4927ada30c9f8c3b520be1b5fd02a5da15bc10bff3e", + "https://bcr.bazel.build/modules/apple_support/1.21.1/MODULE.bazel": "5809fa3efab15d1f3c3c635af6974044bac8a4919c62238cce06acee8a8c11f1", "https://bcr.bazel.build/modules/apple_support/1.24.1/MODULE.bazel": "f46e8ddad60aef170ee92b2f3d00ef66c147ceafea68b6877cb45bd91737f5f8", + "https://bcr.bazel.build/modules/apple_support/1.24.2/MODULE.bazel": "0e62471818affb9f0b26f128831d5c40b074d32e6dda5a0d3852847215a41ca4", "https://bcr.bazel.build/modules/apple_support/2.3.0/MODULE.bazel": "d48f824ae8eeea5f837eb3038cef3615075d996d3e82eb9187192c2820605a81", "https://bcr.bazel.build/modules/apple_support/2.3.0/source.json": "d99b0a50918c4484856d773026b2fd60a694668c70fc0e19d592786dc7e5e469", "https://bcr.bazel.build/modules/aspect_bazel_lib/2.14.0/MODULE.bazel": "2b31ffcc9bdc8295b2167e07a757dbbc9ac8906e7028e5170a3708cecaac119f", @@ -32,6 +34,7 @@ "https://bcr.bazel.build/modules/aspect_bazel_lib/2.8.1/MODULE.bazel": "812d2dd42f65dca362152101fbec418029cc8fd34cbad1a2fde905383d705838", "https://bcr.bazel.build/modules/bazel_features/1.1.0/MODULE.bazel": "cfd42ff3b815a5f39554d97182657f8c4b9719568eb7fded2b9135f084bf760b", "https://bcr.bazel.build/modules/bazel_features/1.1.1/MODULE.bazel": "27b8c79ef57efe08efccbd9dd6ef70d61b4798320b8d3c134fd571f78963dbcd", + "https://bcr.bazel.build/modules/bazel_features/1.10.0/MODULE.bazel": "f75e8807570484a99be90abcd52b5e1f390362c258bcb73106f4544957a48101", "https://bcr.bazel.build/modules/bazel_features/1.11.0/MODULE.bazel": "f9382337dd5a474c3b7d334c2f83e50b6eaedc284253334cf823044a26de03e8", "https://bcr.bazel.build/modules/bazel_features/1.13.0/MODULE.bazel": "c14c33c7c3c730612bdbe14ebbb5e61936b6f11322ea95a6e91cd1ba962f94df", "https://bcr.bazel.build/modules/bazel_features/1.15.0/MODULE.bazel": "d38ff6e517149dc509406aca0db3ad1efdd890a85e049585b7234d04238e2a4d", @@ -49,8 +52,9 @@ "https://bcr.bazel.build/modules/bazel_features/1.34.0/MODULE.bazel": "e8475ad7c8965542e0c7aac8af68eb48c4af904be3d614b6aa6274c092c2ea1e", "https://bcr.bazel.build/modules/bazel_features/1.38.0/MODULE.bazel": "f9b8a9c890ebd216b4049fd12a31d3c2602e3403c7af636b04fbbd7453edc9c9", "https://bcr.bazel.build/modules/bazel_features/1.39.0/MODULE.bazel": "28739425c1fc283c91931619749c832b555e60bcd1010b40d8441ce0a5cf726d", - "https://bcr.bazel.build/modules/bazel_features/1.39.0/source.json": "f63cbeb4c602098484d57001e5a07d31cb02bbccde9b5e2c9bf0b29d05283e93", "https://bcr.bazel.build/modules/bazel_features/1.4.1/MODULE.bazel": "e45b6bb2350aff3e442ae1111c555e27eac1d915e77775f6fdc4b351b758b5d7", + "https://bcr.bazel.build/modules/bazel_features/1.42.1/MODULE.bazel": "275a59b5406ff18c01739860aa70ad7ccb3cfb474579411decca11c93b951080", + "https://bcr.bazel.build/modules/bazel_features/1.42.1/source.json": "fcd4396b2df85f64f2b3bb436ad870793ecf39180f1d796f913cc9276d355309", "https://bcr.bazel.build/modules/bazel_features/1.9.0/MODULE.bazel": "885151d58d90d8d9c811eb75e3288c11f850e1d6b481a8c9f766adee4712358b", "https://bcr.bazel.build/modules/bazel_features/1.9.1/MODULE.bazel": "8f679097876a9b609ad1f60249c49d68bfab783dd9be012faf9d82547b14815a", "https://bcr.bazel.build/modules/bazel_lib/3.0.0/MODULE.bazel": "22b70b80ac89ad3f3772526cd9feee2fa412c2b01933fea7ed13238a448d370d", @@ -75,8 +79,8 @@ "https://bcr.bazel.build/modules/bazel_worker_api/0.0.8/source.json": "abaf8ac9d2ab2f47bda9af4c0c080ff7907378888e1f4bc62a0539dd13ba61e8", "https://bcr.bazel.build/modules/bazel_worker_java/0.0.8/MODULE.bazel": "e76479eae70bd4e8f5f4c2dfc5d03ab971cfb18750246c7b3f3454c5c2ee6629", "https://bcr.bazel.build/modules/bazel_worker_java/0.0.8/source.json": "9395c4679444bc47bf7e51a710366a4480aa371c6f6bed01868e2fabcf11acec", - "https://bcr.bazel.build/modules/buildozer/7.1.2/MODULE.bazel": "2e8dd40ede9c454042645fd8d8d0cd1527966aa5c919de86661e62953cd73d84", - "https://bcr.bazel.build/modules/buildozer/7.1.2/source.json": "c9028a501d2db85793a6996205c8de120944f50a0d570438fcae0457a5f9d1f8", + "https://bcr.bazel.build/modules/buildozer/8.5.1/MODULE.bazel": "a35d9561b3fc5b18797c330793e99e3b834a473d5fbd3d7d7634aafc9bdb6f8f", + "https://bcr.bazel.build/modules/buildozer/8.5.1/source.json": "e3386e6ff4529f2442800dee47ad28d3e6487f36a1f75ae39ae56c70f0cd2fbd", "https://bcr.bazel.build/modules/dragonbox/0.0.0-241028-6c7c925.envoy/MODULE.bazel": "not found", "https://bcr.bazel.build/modules/fast_float/8.0.2/MODULE.bazel": "43504664efdfa4c6cf1349626c87135c9b87926325c720458f396eee25568eda", "https://bcr.bazel.build/modules/fast_float/8.0.2/source.json": "8b83304ea4c3c1e43cc74e644918394a799b0f2cebe3b9ffbbe37ac75dcfb171", @@ -134,7 +138,6 @@ "https://bcr.bazel.build/modules/protobuf/29.0-rc2.bcr.1/MODULE.bazel": "52f4126f63a2f0bbf36b99c2a87648f08467a4eaf92ba726bc7d6a500bbf770c", "https://bcr.bazel.build/modules/protobuf/29.0-rc2/MODULE.bazel": "6241d35983510143049943fc0d57937937122baf1b287862f9dc8590fc4c37df", "https://bcr.bazel.build/modules/protobuf/29.0-rc3/MODULE.bazel": "33c2dfa286578573afc55a7acaea3cada4122b9631007c594bf0729f41c8de92", - "https://bcr.bazel.build/modules/protobuf/29.0/MODULE.bazel": "319dc8bf4c679ff87e71b1ccfb5a6e90a6dbc4693501d471f48662ac46d04e4e", "https://bcr.bazel.build/modules/protobuf/29.1/MODULE.bazel": "557c3457560ff49e122ed76c0bc3397a64af9574691cb8201b4e46d4ab2ecb95", "https://bcr.bazel.build/modules/protobuf/3.19.0/MODULE.bazel": "6b5fbb433f760a99a22b18b6850ed5784ef0e9928a72668b66e4d7ccd47db9b0", "https://bcr.bazel.build/modules/protobuf/3.19.2/MODULE.bazel": "532ffe5f2186b69fdde039efe6df13ba726ff338c6bc82275ad433013fa10573", @@ -154,10 +157,10 @@ "https://bcr.bazel.build/modules/rules_android/0.7.1/MODULE.bazel": "a806fc382a774252f228a40e3b11b9fcc6276f8778c7fb33e9f72937c6258363", "https://bcr.bazel.build/modules/rules_android/0.7.1/source.json": "151440aed3f0f73a00d4ed5cec5d31f63a6fef9b95d8fab1eb1810150fa525f2", "https://bcr.bazel.build/modules/rules_apple/3.16.0/MODULE.bazel": "0d1caf0b8375942ce98ea944be754a18874041e4e0459401d925577624d3a54a", + "https://bcr.bazel.build/modules/rules_apple/4.1.0/MODULE.bazel": "76e10fd4a48038d3fc7c5dc6e63b7063bbf5304a2e3bd42edda6ec660eebea68", "https://bcr.bazel.build/modules/rules_cc/0.0.1/MODULE.bazel": "cb2aa0747f84c6c3a78dad4e2049c154f08ab9d166b1273835a8174940365647", "https://bcr.bazel.build/modules/rules_cc/0.0.10/MODULE.bazel": "ec1705118f7eaedd6e118508d3d26deba2a4e76476ada7e0e3965211be012002", "https://bcr.bazel.build/modules/rules_cc/0.0.13/MODULE.bazel": "0e8529ed7b323dad0775ff924d2ae5af7640b23553dfcd4d34344c7e7a867191", - "https://bcr.bazel.build/modules/rules_cc/0.0.14/MODULE.bazel": "5e343a3aac88b8d7af3b1b6d2093b55c347b8eefc2e7d1442f7a02dc8fea48ac", "https://bcr.bazel.build/modules/rules_cc/0.0.15/MODULE.bazel": "6704c35f7b4a72502ee81f61bf88706b54f06b3cbe5558ac17e2e14666cd5dcc", "https://bcr.bazel.build/modules/rules_cc/0.0.16/MODULE.bazel": "7661303b8fc1b4d7f532e54e9d6565771fea666fbdf839e0a86affcd02defe87", "https://bcr.bazel.build/modules/rules_cc/0.0.17/MODULE.bazel": "2ae1d8f4238ec67d7185d8861cb0a2cdf4bc608697c331b95bf990e69b62e64a", @@ -166,6 +169,7 @@ "https://bcr.bazel.build/modules/rules_cc/0.0.8/MODULE.bazel": "964c85c82cfeb6f3855e6a07054fdb159aced38e99a5eecf7bce9d53990afa3e", "https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel": "836e76439f354b89afe6a911a7adf59a6b2518fafb174483ad78a2a2fde7b1c5", "https://bcr.bazel.build/modules/rules_cc/0.1.1/MODULE.bazel": "2f0222a6f229f0bf44cd711dc13c858dad98c62d52bd51d8fc3a764a83125513", + "https://bcr.bazel.build/modules/rules_cc/0.1.2/MODULE.bazel": "557ddc3a96858ec0d465a87c0a931054d7dcfd6583af2c7ed3baf494407fd8d0", "https://bcr.bazel.build/modules/rules_cc/0.1.5/MODULE.bazel": "88dfc9361e8b5ae1008ac38f7cdfd45ad738e4fa676a3ad67d19204f045a1fd8", "https://bcr.bazel.build/modules/rules_cc/0.2.0/MODULE.bazel": "b5c17f90458caae90d2ccd114c81970062946f49f355610ed89bebf954f5783c", "https://bcr.bazel.build/modules/rules_cc/0.2.13/MODULE.bazel": "eecdd666eda6be16a8d9dc15e44b5c75133405e820f620a234acc4b1fdc5aa37", @@ -199,12 +203,12 @@ "https://bcr.bazel.build/modules/rules_java/7.3.2/MODULE.bazel": "50dece891cfdf1741ea230d001aa9c14398062f2b7c066470accace78e412bc2", "https://bcr.bazel.build/modules/rules_java/7.4.0/MODULE.bazel": "a592852f8a3dd539e82ee6542013bf2cadfc4c6946be8941e189d224500a8934", "https://bcr.bazel.build/modules/rules_java/7.6.1/MODULE.bazel": "2f14b7e8a1aa2f67ae92bc69d1ec0fa8d9f827c4e17ff5e5f02e91caa3b2d0fe", - "https://bcr.bazel.build/modules/rules_java/8.14.0/MODULE.bazel": "717717ed40cc69994596a45aec6ea78135ea434b8402fb91b009b9151dd65615", "https://bcr.bazel.build/modules/rules_java/8.3.2/MODULE.bazel": "7336d5511ad5af0b8615fdc7477535a2e4e723a357b6713af439fe8cf0195017", "https://bcr.bazel.build/modules/rules_java/8.5.1/MODULE.bazel": "d8a9e38cc5228881f7055a6079f6f7821a073df3744d441978e7a43e20226939", "https://bcr.bazel.build/modules/rules_java/8.6.0/MODULE.bazel": "9c064c434606d75a086f15ade5edb514308cccd1544c2b2a89bbac4310e41c71", "https://bcr.bazel.build/modules/rules_java/8.6.1/MODULE.bazel": "f4808e2ab5b0197f094cabce9f4b006a27766beb6a9975931da07099560ca9c2", "https://bcr.bazel.build/modules/rules_java/8.9.0/MODULE.bazel": "e17c876cb53dcd817b7b7f0d2985b710610169729e8c371b2221cacdcd3dce4a", + "https://bcr.bazel.build/modules/rules_java/9.1.0/MODULE.bazel": "ee63f27e36a3fada80342869361182f120a9819c74320e8e65b1e04ba0cd7a9d", "https://bcr.bazel.build/modules/rules_java/9.3.0/MODULE.bazel": "f657c72d65ac449caae9abf2e68e66c0d36f9416848c4c4903d0b3234229e7f2", "https://bcr.bazel.build/modules/rules_java/9.3.0/source.json": "59ae7e662c3c7042b88bbb42ad12483523e234c65ebe4c51611baa43e85cb248", "https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel": "a56b85e418c83eb1839819f0b515c431010160383306d13ec21959ac412d2fe7", @@ -246,11 +250,12 @@ "https://bcr.bazel.build/modules/rules_python/0.33.2/MODULE.bazel": "3e036c4ad8d804a4dad897d333d8dce200d943df4827cb849840055be8d2e937", "https://bcr.bazel.build/modules/rules_python/0.37.2/MODULE.bazel": "b5ffde91410745750b6c13be1c5dc4555ef5bc50562af4a89fd77807fdde626a", "https://bcr.bazel.build/modules/rules_python/0.4.0/MODULE.bazel": "9208ee05fd48bf09ac60ed269791cf17fb343db56c8226a720fbb1cdf467166c", - "https://bcr.bazel.build/modules/rules_python/0.40.0/MODULE.bazel": "9d1a3cd88ed7d8e39583d9ffe56ae8a244f67783ae89b60caafc9f5cf318ada7", "https://bcr.bazel.build/modules/rules_python/1.0.0/MODULE.bazel": "898a3d999c22caa585eb062b600f88654bf92efb204fa346fb55f6f8edffca43", "https://bcr.bazel.build/modules/rules_python/1.2.0/MODULE.bazel": "5aeeb48b2a6c19d668b48adf2b8a2b209a6310c230db0ce77450f148a89846e4", + "https://bcr.bazel.build/modules/rules_python/1.3.0/MODULE.bazel": "8361d57eafb67c09b75bf4bbe6be360e1b8f4f18118ab48037f2bd50aa2ccb13", "https://bcr.bazel.build/modules/rules_python/1.4.1/MODULE.bazel": "8991ad45bdc25018301d6b7e1d3626afc3c8af8aaf4bc04f23d0b99c938b73a6", "https://bcr.bazel.build/modules/rules_python/1.6.0/MODULE.bazel": "7e04ad8f8d5bea40451cf80b1bd8262552aa73f841415d20db96b7241bd027d8", + "https://bcr.bazel.build/modules/rules_python/1.7.0/MODULE.bazel": "d01f995ecd137abf30238ad9ce97f8fc3ac57289c8b24bd0bf53324d937a14f8", "https://bcr.bazel.build/modules/rules_python/2.2.0/MODULE.bazel": "9ce85518b14625a3abec3c95e3fa739ab0578e58240ef829af20efebcdebc41a", "https://bcr.bazel.build/modules/rules_python/2.2.0/source.json": "274b1ca2363520292527f21b8237aa0f562003ea5912ad07d96d98e87738f618", "https://bcr.bazel.build/modules/rules_robolectric/4.14.1.2/MODULE.bazel": "d44fec647d0aeb67b9f3b980cf68ba634976f3ae7ccd6c07d790b59b87a4f251", @@ -265,6 +270,8 @@ "https://bcr.bazel.build/modules/rules_shell/0.8.0/source.json": "eb53cc815bc503c6683c5fe12d943f98883f81fc22f51403ec8a95610cba4195", "https://bcr.bazel.build/modules/rules_swift/1.16.0/MODULE.bazel": "4a09f199545a60d09895e8281362b1ff3bb08bbde69c6fc87aff5b92fcc916ca", "https://bcr.bazel.build/modules/rules_swift/2.1.1/MODULE.bazel": "494900a80f944fc7aa61500c2073d9729dff0b764f0e89b824eb746959bc1046", + "https://bcr.bazel.build/modules/rules_swift/2.4.0/MODULE.bazel": "1639617eb1ede28d774d967a738b4a68b0accb40650beadb57c21846beab5efd", + "https://bcr.bazel.build/modules/rules_swift/3.1.2/MODULE.bazel": "72c8f5cf9d26427cee6c76c8e3853eb46ce6b0412a081b2b6db6e8ad56267400", "https://bcr.bazel.build/modules/simdutf/8.1.0.envoy/MODULE.bazel": "not found", "https://bcr.bazel.build/modules/stardoc/0.5.1/MODULE.bazel": "1a05d92974d0c122f5ccf09291442580317cdd859f07a8655f1db9a60374f9f8", "https://bcr.bazel.build/modules/stardoc/0.5.3/MODULE.bazel": "c7f6948dae6999bf0db32c1858ae345f112cacf98f174c7a8bb707e41b974f1c", @@ -275,6 +282,7 @@ "https://bcr.bazel.build/modules/stardoc/0.7.2/MODULE.bazel": "fc152419aa2ea0f51c29583fab1e8c99ddefd5b3778421845606ee628629e0e5", "https://bcr.bazel.build/modules/stardoc/0.7.2/source.json": "58b029e5e901d6802967754adf0a9056747e8176f017cfe3607c0851f4d42216", "https://bcr.bazel.build/modules/swift_argument_parser/1.3.1.1/MODULE.bazel": "5e463fbfba7b1701d957555ed45097d7f984211330106ccd1352c6e0af0dcf91", + "https://bcr.bazel.build/modules/swift_argument_parser/1.3.1.2/MODULE.bazel": "75aab2373a4bbe2a1260b9bf2a1ebbdbf872d3bd36f80bff058dccd82e89422f", "https://bcr.bazel.build/modules/tar.bzl/0.2.1/MODULE.bazel": "52d1c00a80a8cc67acbd01649e83d8dd6a9dc426a6c0b754a04fe8c219c76468", "https://bcr.bazel.build/modules/tar.bzl/0.5.1/MODULE.bazel": "7c2eb3dcfc53b0f3d6f9acdfd911ca803eaf92aadf54f8ca6e4c1f3aee288351", "https://bcr.bazel.build/modules/tar.bzl/0.6.0/MODULE.bazel": "a3584b4edcfafcabd9b0ef9819808f05b372957bbdff41601429d5fd0aac2e7c", @@ -293,32 +301,30 @@ "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/MODULE.bazel": "eec517b5bbe5492629466e11dae908d043364302283de25581e3eb944326c4ca", "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/source.json": "22bc55c47af97246cfc093d0acf683a7869377de362b5d1c552c2c2e16b7a806", "https://bcr.bazel.build/modules/zlib/1.3.1/MODULE.bazel": "751c9940dcfe869f5f7274e1295422a34623555916eb98c174c1e945594bf198", - "https://raw.githubusercontent.com/envoyproxy/bazel-registry/a126e386f21fe8c74dce2515d87c302596b5d133/bazel_registry.json": "51bd3a0b193753e419c5d3db38e92fbcb9f7f97fd992ef2e24a0addd7274b37a", - "https://raw.githubusercontent.com/envoyproxy/bazel-registry/a126e386f21fe8c74dce2515d87c302596b5d133/modules/dragonbox/0.0.0-241028-6c7c925.envoy/MODULE.bazel": "56dd26c839325bc2c40cc1879c00cab3397cd83fe3cf6ab8ccaf7fd6ad1b890d", - "https://raw.githubusercontent.com/envoyproxy/bazel-registry/a126e386f21fe8c74dce2515d87c302596b5d133/modules/dragonbox/0.0.0-241028-6c7c925.envoy/source.json": "642addb5bea17b6570a138ccfb4f50f34c810c9e3416748a09e1ac723b01021f", - "https://raw.githubusercontent.com/envoyproxy/bazel-registry/a126e386f21fe8c74dce2515d87c302596b5d133/modules/fp16/0.0.0-260704-3d2de18.envoy/MODULE.bazel": "27e5020ea158fdc725eafed3443b6fa9a1555d52505dafcdc3e6ea74d9e112c1", - "https://raw.githubusercontent.com/envoyproxy/bazel-registry/a126e386f21fe8c74dce2515d87c302596b5d133/modules/fp16/0.0.0-260704-3d2de18.envoy/source.json": "ccc308b4d5afbba59ce93809243da68a5402414bb7f707d2b691df68ab896250", - "https://raw.githubusercontent.com/envoyproxy/bazel-registry/a126e386f21fe8c74dce2515d87c302596b5d133/modules/icu/78.2.envoy/MODULE.bazel": "bed492d3dffffca822867b4b034191069ea917cd5c1b98ad3c5e609227d0f387", - "https://raw.githubusercontent.com/envoyproxy/bazel-registry/a126e386f21fe8c74dce2515d87c302596b5d133/modules/icu/78.2.envoy/source.json": "d3c0d7c00cdb28b6294356ec253a0ee994e2d65f912b92075ea5ddd049df283b", - "https://raw.githubusercontent.com/envoyproxy/bazel-registry/a126e386f21fe8c74dce2515d87c302596b5d133/modules/protobuf/35.1.bcr.envoy/MODULE.bazel": "a42d2e15b0ffb57474df57e2cc274aa9ad2e52e6e9e7bc19e9c529b0d4093d5f", - "https://raw.githubusercontent.com/envoyproxy/bazel-registry/a126e386f21fe8c74dce2515d87c302596b5d133/modules/protobuf/35.1.bcr.envoy/source.json": "5ee2c32f315c4be232f955a963f37e631f70a4d32cd3dd536b46c48920a98944", - "https://raw.githubusercontent.com/envoyproxy/bazel-registry/a126e386f21fe8c74dce2515d87c302596b5d133/modules/simdutf/8.1.0.envoy/MODULE.bazel": "d7288f3bd5168bc92aff3591e5f7a3a58277bddcc7fc70fa125f39ac9445f4b7", - "https://raw.githubusercontent.com/envoyproxy/bazel-registry/a126e386f21fe8c74dce2515d87c302596b5d133/modules/simdutf/8.1.0.envoy/source.json": "b95d6bfb222cf92c83d3352ec0c550394d801e2b2700b160b692cbe4b40b8342", - "https://raw.githubusercontent.com/envoyproxy/bazel-registry/a126e386f21fe8c74dce2515d87c302596b5d133/modules/toolchains_llvm/1.8.0.envoy/MODULE.bazel": "93909b69ee77410306b1b591653f7f89ecda4c7d88d42c468dd1e5e7afc6fe65", - "https://raw.githubusercontent.com/envoyproxy/bazel-registry/a126e386f21fe8c74dce2515d87c302596b5d133/modules/toolchains_llvm/1.9.0.envoy/MODULE.bazel": "f3a85560662c37a739cbe00f20a527baf0caa9508c0541840877481479c0c825", - "https://raw.githubusercontent.com/envoyproxy/bazel-registry/a126e386f21fe8c74dce2515d87c302596b5d133/modules/toolchains_llvm/1.9.0.envoy/source.json": "67e2d7bbdb368463c599a87fcc2c1884ca6ac0a339d5ac999ca8b5c34ec0911d", - "https://raw.githubusercontent.com/envoyproxy/bazel-registry/a126e386f21fe8c74dce2515d87c302596b5d133/modules/v8/14.6.202.10.envoy/MODULE.bazel": "57fa395049458e9768b26e4789236ee620bd177414bf979cf583887f06c71749", - "https://raw.githubusercontent.com/envoyproxy/bazel-registry/a126e386f21fe8c74dce2515d87c302596b5d133/modules/v8/14.6.202.10.envoy/source.json": "068a8822f21c1c488982f6b3fd5c52858e8db025ebc3458170d3ed940b425a57" + "https://raw.githubusercontent.com/envoyproxy/bazel-registry/76440e57c1495e6e6b26e30069d42050a8ca5acb/bazel_registry.json": "51bd3a0b193753e419c5d3db38e92fbcb9f7f97fd992ef2e24a0addd7274b37a", + "https://raw.githubusercontent.com/envoyproxy/bazel-registry/76440e57c1495e6e6b26e30069d42050a8ca5acb/modules/dragonbox/0.0.0-241028-6c7c925.envoy/MODULE.bazel": "56dd26c839325bc2c40cc1879c00cab3397cd83fe3cf6ab8ccaf7fd6ad1b890d", + "https://raw.githubusercontent.com/envoyproxy/bazel-registry/76440e57c1495e6e6b26e30069d42050a8ca5acb/modules/dragonbox/0.0.0-241028-6c7c925.envoy/source.json": "642addb5bea17b6570a138ccfb4f50f34c810c9e3416748a09e1ac723b01021f", + "https://raw.githubusercontent.com/envoyproxy/bazel-registry/76440e57c1495e6e6b26e30069d42050a8ca5acb/modules/fp16/0.0.0-260704-3d2de18.envoy/MODULE.bazel": "27e5020ea158fdc725eafed3443b6fa9a1555d52505dafcdc3e6ea74d9e112c1", + "https://raw.githubusercontent.com/envoyproxy/bazel-registry/76440e57c1495e6e6b26e30069d42050a8ca5acb/modules/fp16/0.0.0-260704-3d2de18.envoy/source.json": "ccc308b4d5afbba59ce93809243da68a5402414bb7f707d2b691df68ab896250", + "https://raw.githubusercontent.com/envoyproxy/bazel-registry/76440e57c1495e6e6b26e30069d42050a8ca5acb/modules/icu/78.2.envoy/MODULE.bazel": "bed492d3dffffca822867b4b034191069ea917cd5c1b98ad3c5e609227d0f387", + "https://raw.githubusercontent.com/envoyproxy/bazel-registry/76440e57c1495e6e6b26e30069d42050a8ca5acb/modules/icu/78.2.envoy/source.json": "d3c0d7c00cdb28b6294356ec253a0ee994e2d65f912b92075ea5ddd049df283b", + "https://raw.githubusercontent.com/envoyproxy/bazel-registry/76440e57c1495e6e6b26e30069d42050a8ca5acb/modules/protobuf/35.1.bcr.envoy/MODULE.bazel": "a42d2e15b0ffb57474df57e2cc274aa9ad2e52e6e9e7bc19e9c529b0d4093d5f", + "https://raw.githubusercontent.com/envoyproxy/bazel-registry/76440e57c1495e6e6b26e30069d42050a8ca5acb/modules/protobuf/35.1.bcr.envoy/source.json": "5ee2c32f315c4be232f955a963f37e631f70a4d32cd3dd536b46c48920a98944", + "https://raw.githubusercontent.com/envoyproxy/bazel-registry/76440e57c1495e6e6b26e30069d42050a8ca5acb/modules/simdutf/8.1.0.envoy/MODULE.bazel": "d7288f3bd5168bc92aff3591e5f7a3a58277bddcc7fc70fa125f39ac9445f4b7", + "https://raw.githubusercontent.com/envoyproxy/bazel-registry/76440e57c1495e6e6b26e30069d42050a8ca5acb/modules/simdutf/8.1.0.envoy/source.json": "b95d6bfb222cf92c83d3352ec0c550394d801e2b2700b160b692cbe4b40b8342", + "https://raw.githubusercontent.com/envoyproxy/bazel-registry/76440e57c1495e6e6b26e30069d42050a8ca5acb/modules/toolchains_llvm/1.8.0.envoy/MODULE.bazel": "93909b69ee77410306b1b591653f7f89ecda4c7d88d42c468dd1e5e7afc6fe65", + "https://raw.githubusercontent.com/envoyproxy/bazel-registry/76440e57c1495e6e6b26e30069d42050a8ca5acb/modules/toolchains_llvm/1.9.0.envoy/MODULE.bazel": "f3a85560662c37a739cbe00f20a527baf0caa9508c0541840877481479c0c825", + "https://raw.githubusercontent.com/envoyproxy/bazel-registry/76440e57c1495e6e6b26e30069d42050a8ca5acb/modules/toolchains_llvm/1.9.0.envoy/source.json": "67e2d7bbdb368463c599a87fcc2c1884ca6ac0a339d5ac999ca8b5c34ec0911d", + "https://raw.githubusercontent.com/envoyproxy/bazel-registry/76440e57c1495e6e6b26e30069d42050a8ca5acb/modules/v8/14.6.202.10.envoy/MODULE.bazel": "57fa395049458e9768b26e4789236ee620bd177414bf979cf583887f06c71749", + "https://raw.githubusercontent.com/envoyproxy/bazel-registry/76440e57c1495e6e6b26e30069d42050a8ca5acb/modules/v8/14.6.202.10.envoy/source.json": "068a8822f21c1c488982f6b3fd5c52858e8db025ebc3458170d3ed940b425a57" }, "selectedYankedVersions": {}, "moduleExtensions": { "//compile:extensions.bzl%libcxx_extension": { "general": { - "bzlTransitiveDigest": "G/GH44cjY6wlnZEwWmvHkcNdAdZzFZ+1txwMfbYffZ4=", - "usagesDigest": "y4Q8/OHUodqeqYFwT/Dh6kGVc3RcORSJIuy06M/HAsY=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, + "bzlTransitiveDigest": "n0LvzKP3JAl1+o6doTrtIK1Cog9WVZxkjucbNUVhJk0=", + "usagesDigest": "Q5p3Ts3ttrpJaL9rob1jBP7fFCbdDpufcd1XX/Bp2fk=", + "recordedInputs": [], "generatedRepoSpecs": { "llvm_libcxx_aarch64": { "repoRuleId": "@@//compile:llvm_prebuilt.bzl%llvm_prebuilt", @@ -336,22 +342,19 @@ "url": "https://github.com/llvm/llvm-project/releases/download/llvmorg-22.1.8/LLVM-22.1.8-Linux-X64.tar.xz" } } - }, - "recordedRepoMappingEntries": [] + } } }, "//compile:extensions.bzl%libcxx_libs_extension": { "general": { - "bzlTransitiveDigest": "G/GH44cjY6wlnZEwWmvHkcNdAdZzFZ+1txwMfbYffZ4=", - "usagesDigest": "WGLlE+LyBlwJgqcy7T1SulsGcIEfdJP7sOvnAUOVhN4=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, + "bzlTransitiveDigest": "n0LvzKP3JAl1+o6doTrtIK1Cog9WVZxkjucbNUVhJk0=", + "usagesDigest": "pkMz/DUdTi3IZw7AZmAxYq96IlSBAA5vm7WBBw4Itss=", + "recordedInputs": [], "generatedRepoSpecs": { "libcxx_libs_aarch64": { "repoRuleId": "@@//compile:libcxx_libs.bzl%libcxx_libs", "attributes": { - "version": "0.2.9", + "version": "0.2.14", "sha256": "b3bd8dfc1c250d5c2c36de174138ffef9754402b33e54abe9b5efb25982fa2f7", "arch": "aarch64" } @@ -359,22 +362,19 @@ "libcxx_libs_x86_64": { "repoRuleId": "@@//compile:libcxx_libs.bzl%libcxx_libs", "attributes": { - "version": "0.2.9", + "version": "0.2.14", "sha256": "e40f39338ffe561dfa26541557c9e548fc7760db9d99f7b6c5de237b725482aa", "arch": "x86_64" } } - }, - "recordedRepoMappingEntries": [] + } } }, "//compile:extensions.bzl%llvm_minimal_build_extension": { "general": { - "bzlTransitiveDigest": "G/GH44cjY6wlnZEwWmvHkcNdAdZzFZ+1txwMfbYffZ4=", - "usagesDigest": "NCpK+4w39uxhSXpaGA4yQ6/z003ZRGW4JrTDl1gySFk=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, + "bzlTransitiveDigest": "n0LvzKP3JAl1+o6doTrtIK1Cog9WVZxkjucbNUVhJk0=", + "usagesDigest": "AfWLlk7q58Sdl3prnEQktaPcLElx4eT7ShLcSW5QMfk=", + "recordedInputs": [], "generatedRepoSpecs": { "llvm_tarball_linux_x86_64": { "repoRuleId": "@@//compile:llvm_minimal.bzl%llvm_tarball", @@ -403,22 +403,19 @@ "platform": "macOS-ARM64" } } - }, - "recordedRepoMappingEntries": [] + } } }, "//compile:extensions.bzl%llvm_minimal_extension": { "general": { - "bzlTransitiveDigest": "iGhoyv/rCamuOdT7NVhoofJc2Gsxlkdl9ymm3SgqLFo=", - "usagesDigest": "ZqLfAjRhUAMAeJiS/eI2hiP3v3uIOtSBvc703K/qOb0=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, + "bzlTransitiveDigest": "n0LvzKP3JAl1+o6doTrtIK1Cog9WVZxkjucbNUVhJk0=", + "usagesDigest": "DV2AgZy5Sn1W2An5MbFce8gCvOt7LZOKqmViARTw+s4=", + "recordedInputs": [], "generatedRepoSpecs": { "llvm_minimal_linux_x64": { "repoRuleId": "@@//compile:llvm_minimal.bzl%llvm_minimal_repo", "attributes": { - "url": "https://github.com/envoyproxy/toolshed/releases/download/bins-v0.2.11/llvm-minimal-22.1.8-Linux-X64.tar.zst", + "url": "https://github.com/envoyproxy/toolshed/releases/download/bins-v0.2.14/llvm-minimal-22.1.8-Linux-X64.tar.zst", "sha256": "6cb4cca6df33be00c80fa1639062c973d1cafe4e7ad98a9b4bdf21bf9dec5806", "strip_prefix": "llvm-minimal-22.1.8-Linux-X64" } @@ -426,7 +423,7 @@ "llvm_minimal_linux_arm64": { "repoRuleId": "@@//compile:llvm_minimal.bzl%llvm_minimal_repo", "attributes": { - "url": "https://github.com/envoyproxy/toolshed/releases/download/bins-v0.2.11/llvm-minimal-22.1.8-Linux-ARM64.tar.zst", + "url": "https://github.com/envoyproxy/toolshed/releases/download/bins-v0.2.14/llvm-minimal-22.1.8-Linux-ARM64.tar.zst", "sha256": "9a6cc0a84d524342e578db739b04e8a3875adb40b38887e4e074661e925f8a9c", "strip_prefix": "llvm-minimal-22.1.8-Linux-ARM64" } @@ -434,27 +431,24 @@ "llvm_minimal_macos_arm64": { "repoRuleId": "@@//compile:llvm_minimal.bzl%llvm_minimal_repo", "attributes": { - "url": "https://github.com/envoyproxy/toolshed/releases/download/bins-v0.2.11/llvm-minimal-22.1.8-macOS-ARM64.tar.zst", + "url": "https://github.com/envoyproxy/toolshed/releases/download/bins-v0.2.14/llvm-minimal-22.1.8-macOS-ARM64.tar.zst", "sha256": "928e51aa7c97fbb8c5c50075118f4b36e36363b1a2c3af2dfef9aea1ef526ade", "strip_prefix": "llvm-minimal-22.1.8-macOS-ARM64" } } - }, - "recordedRepoMappingEntries": [] + } } }, "//compile:extensions.bzl%llvm_toolchain_alias_extension": { "general": { - "bzlTransitiveDigest": "G/GH44cjY6wlnZEwWmvHkcNdAdZzFZ+1txwMfbYffZ4=", - "usagesDigest": "uWO75d9O0kcL3vMT7TyGSHvbrJIp0/gDyo9vXEEY5Zw=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, + "bzlTransitiveDigest": "n0LvzKP3JAl1+o6doTrtIK1Cog9WVZxkjucbNUVhJk0=", + "usagesDigest": "o42TmdCpxDB0dNsptcLd/UNCVAH+5/AHtXo44U6H5h4=", + "recordedInputs": [], "generatedRepoSpecs": { "llvm_minimal_linux_x64": { "repoRuleId": "@@//compile:llvm_minimal.bzl%llvm_minimal_repo", "attributes": { - "url": "https://github.com/envoyproxy/toolshed/releases/download/bins-v0.2.9/llvm-minimal-22.1.8-Linux-X64.tar.zst", + "url": "https://github.com/envoyproxy/toolshed/releases/download/bins-v0.2.14/llvm-minimal-22.1.8-Linux-X64.tar.zst", "sha256": "6cb4cca6df33be00c80fa1639062c973d1cafe4e7ad98a9b4bdf21bf9dec5806", "strip_prefix": "llvm-minimal-22.1.8-Linux-X64" } @@ -462,7 +456,7 @@ "llvm_minimal_linux_arm64": { "repoRuleId": "@@//compile:llvm_minimal.bzl%llvm_minimal_repo", "attributes": { - "url": "https://github.com/envoyproxy/toolshed/releases/download/bins-v0.2.9/llvm-minimal-22.1.8-Linux-ARM64.tar.zst", + "url": "https://github.com/envoyproxy/toolshed/releases/download/bins-v0.2.14/llvm-minimal-22.1.8-Linux-ARM64.tar.zst", "sha256": "9a6cc0a84d524342e578db739b04e8a3875adb40b38887e4e074661e925f8a9c", "strip_prefix": "llvm-minimal-22.1.8-Linux-ARM64" } @@ -470,7 +464,7 @@ "llvm_minimal_macos_arm64": { "repoRuleId": "@@//compile:llvm_minimal.bzl%llvm_minimal_repo", "attributes": { - "url": "https://github.com/envoyproxy/toolshed/releases/download/bins-v0.2.9/llvm-minimal-22.1.8-macOS-ARM64.tar.zst", + "url": "https://github.com/envoyproxy/toolshed/releases/download/bins-v0.2.14/llvm-minimal-22.1.8-macOS-ARM64.tar.zst", "sha256": "928e51aa7c97fbb8c5c50075118f4b36e36363b1a2c3af2dfef9aea1ef526ade", "strip_prefix": "llvm-minimal-22.1.8-macOS-ARM64" } @@ -483,17 +477,14 @@ "minimal_macos_arm64": "@@+llvm_toolchain_alias_extension+llvm_minimal_macos_arm64//:BUILD.bazel" } } - }, - "recordedRepoMappingEntries": [] + } } }, "//dependency/test:reachability_test_extension.bzl%reachability_test_extension": { "general": { - "bzlTransitiveDigest": "NqxwhacnUCjbNmVUwIbYGp2Qbml8/4TK6imuNETJWnY=", - "usagesDigest": "JpYNilrJt8/GsPfYlEGn1o5zRlvR7SKmfkifD8YCuzs=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, + "bzlTransitiveDigest": "XQ29jldKZrofMxse6SyWwTha5NHmIp+pOD0+X5RKSRY=", + "usagesDigest": "PofClPiRmRdQd49PXYF9CHN/RpQDShIMwtWonDS8GDY=", + "recordedInputs": [], "generatedRepoSpecs": { "apparent_excluded_transitive_repo": { "repoRuleId": "@@//dependency/test:reachability_test_extension.bzl%_test_repo", @@ -507,17 +498,14 @@ "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nfilegroup(\n name = \"direct\",\n srcs = [\"@apparent_excluded_transitive_repo//:leaf\"],\n)\n" } } - }, - "recordedRepoMappingEntries": [] + } } }, "//sysroot:extensions.bzl%macos_sysroot_build_extension": { "general": { - "bzlTransitiveDigest": "FOSmmvc22vA+YeVHySGYbJvOJk9fO2s5NCh3/JxObds=", - "usagesDigest": "DCjVA8KsZTFyZYgD4DlFoO09sE28RLoFZBbgbyGe5IA=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, + "bzlTransitiveDigest": "uAoRLgi1JRtBcmgRrdu+13YqitvZUnWAHhOfPCOJNmI=", + "usagesDigest": "hWmnJgFItfzE1jilP3LXEXeXeqAhUAoM7dHInzT4BRg=", + "recordedInputs": [], "generatedRepoSpecs": { "pkgutil_linux_amd64": { "repoRuleId": "@@//sysroot:macos_sysroot.bzl%download_file_repo", @@ -539,23 +527,20 @@ "user_agent": "Mozilla/5.0" } } - }, - "recordedRepoMappingEntries": [] + } } }, "//sysroot:extensions.bzl%sysroot_extension": { "general": { - "bzlTransitiveDigest": "PRext/1KRDZnD3QPsbnKQMaXacghUYN2mdYPFjOMm/Q=", - "usagesDigest": "S9rr2cGiXVc4Inmt9v2uEbWMw9zQJ7m6K554kfMS8i0=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, + "bzlTransitiveDigest": "uAoRLgi1JRtBcmgRrdu+13YqitvZUnWAHhOfPCOJNmI=", + "usagesDigest": "8IWELKvFYFZAAKiu9NSRKV5H9Tbi6ipx6JmQR/fiLQE=", + "recordedInputs": [], "generatedRepoSpecs": { "sysroot_linux_amd64": { "repoRuleId": "@@//sysroot:sysroot.bzl%sysroot", "attributes": { - "version": "0.2.11", - "sha256": "63b3b31f7e1a0182816bde18513d72f734e02cc5d2ec50336f04c72c720e4484", + "version": "0.2.14", + "sha256": "e3eba94f01ab0eba6da81fce712f645b2305557f052792b18ab14ec16d665d93", "arch": "amd64", "glibc_version": "2.31", "stdcc_version": "13" @@ -564,30 +549,27 @@ "sysroot_linux_arm64": { "repoRuleId": "@@//sysroot:sysroot.bzl%sysroot", "attributes": { - "version": "0.2.11", - "sha256": "cea58c40b0ced7ff83e1de70879ab904142167d4e0f3caf9e93aecd67845d1c5", + "version": "0.2.14", + "sha256": "40f1f1fa9a8342be444bf94fe1a46ca5eca6091cce83870099ff186ba286e65c", "arch": "arm64", "glibc_version": "2.31", "stdcc_version": "13" } } - }, - "recordedRepoMappingEntries": [] + } } }, "//v8:extensions.bzl%wee8_prebuilt_extension": { "general": { - "bzlTransitiveDigest": "gsXYB+H4d98wucAB/t4R1FvkLoUxhsKECV/2O2Zgq6k=", - "usagesDigest": "7Sk9Z5s6Ry8BI/L+Csf8i6W1AJRSTlQmtJZ9m23Qve8=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, + "bzlTransitiveDigest": "5AUyi7CH/8ae8nMZHY23Ft2e3Sb3ikj9PLEmqOGOZV8=", + "usagesDigest": "GgR3KwZ+Iqq/Rs2jFQz5Q3QD5RYWR1ImrZhMTuHZx/w=", + "recordedInputs": [], "generatedRepoSpecs": { "wee8_prebuilt_x86_64": { "repoRuleId": "@@//v8:wee8_prebuilt.bzl%wee8_prebuilt", "attributes": { - "version": "0.2.9", - "sha256": "4694878d524d11c4d59a515657d2d0693aaa4907c3a30f1767b78b66bf260275", + "version": "0.2.14", + "sha256": "fcb7842467db8412971b90b2ad6c602ba4834b3eaa44fe5a175ae22d4cc0c96c", "arch": "x86_64", "stdlib": "libcxx" } @@ -595,8 +577,8 @@ "wee8_prebuilt_x86_64_libstdcxx": { "repoRuleId": "@@//v8:wee8_prebuilt.bzl%wee8_prebuilt", "attributes": { - "version": "0.2.9", - "sha256": "353a031e31cddd57237a15d52c3f7b0bae6dfb5048605e72792bcb1baa6abd60", + "version": "0.2.14", + "sha256": "02248a38aeef1103a02dc2d65ef20249d42df7aed812f53f63482cee7babe82f", "arch": "x86_64", "stdlib": "libstdcxx" } @@ -604,23 +586,20 @@ "wee8_prebuilt_aarch64": { "repoRuleId": "@@//v8:wee8_prebuilt.bzl%wee8_prebuilt", "attributes": { - "version": "0.2.9", - "sha256": "3a8619a5e0fd55f5bffe87621ad652a7739c96e8a8c3afa11d1d2412c4898136", + "version": "0.2.14", + "sha256": "c1c842e38ade0149eedf6dcd928eb4290cc01be6ebe213f642b161e9f0bb1cdc", "arch": "aarch64", "stdlib": "libcxx" } } - }, - "recordedRepoMappingEntries": [] + } } }, "@@protobuf+//python/dist:system_python.bzl%system_python_extension": { "general": { "bzlTransitiveDigest": "qh0n9IrXU/xS94wxKQrG1J63zrLkA1Wy2Y3BQxptPcI=", "usagesDigest": "DCJhR7LPgXJ//Na7lsN0d5+HulnHLKpkspMdWCAmYDU=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, + "recordedInputs": [], "generatedRepoSpecs": { "system_python": { "repoRuleId": "@@protobuf+//python/dist:system_python.bzl%system_python", @@ -628,19 +607,17 @@ "minimum_python_version": "3.9" } } - }, - "recordedRepoMappingEntries": [] + } } }, "@@pybind11_bazel+//:internal_configure.bzl%internal_configure_extension": { "general": { - "bzlTransitiveDigest": "7zBsfo5dyMqKT23rXrvWqJMx0AugwL6NyirkmvzKcqU=", + "bzlTransitiveDigest": "NRXra7941UfmNUyIxnLt82V5hULluVGL2nBsijTl4j4=", "usagesDigest": "D1r3lfzMuUBFxgG8V6o0bQTLMk3GkaGOaPzw53wrwyw=", - "recordedFileInputs": { - "@@pybind11_bazel+//MODULE.bazel": "e6f4c20442eaa7c90d7190d8dc539d0ab422f95c65a57cc59562170c58ae3d34" - }, - "recordedDirentsInputs": {}, - "envVariables": {}, + "recordedInputs": [ + "REPO_MAPPING:pybind11_bazel+,bazel_tools bazel_tools", + "FILE:@@pybind11_bazel+//MODULE.bazel e6f4c20442eaa7c90d7190d8dc539d0ab422f95c65a57cc59562170c58ae3d34" + ], "generatedRepoSpecs": { "pybind11": { "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", @@ -652,23 +629,16 @@ ] } } - }, - "recordedRepoMappingEntries": [ - [ - "pybind11_bazel+", - "bazel_tools", - "bazel_tools" - ] - ] + } } }, "@@rules_android+//bzlmod_extensions:apksig.bzl%apksig_extension": { "general": { - "bzlTransitiveDigest": "c6mHv2L0P+tWDe7lh/mpzTEedvukBq17Gr9gP16UdxU=", + "bzlTransitiveDigest": "qEcqhUuyYlPmvAtyYRqS+4Y7cRHA2Vho3JIBJZJJX+s=", "usagesDigest": "zr/niBQ/s2fHozWAsg4vI70wAxcuFjG+QtM15qGkq9o=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, + "recordedInputs": [ + "REPO_MAPPING:rules_android+,bazel_tools bazel_tools" + ], "generatedRepoSpecs": { "apksig": { "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", @@ -677,23 +647,16 @@ "build_file": "@@rules_android+//bzlmod_extensions:apksig.BUILD" } } - }, - "recordedRepoMappingEntries": [ - [ - "rules_android+", - "bazel_tools", - "bazel_tools" - ] - ] + } } }, "@@rules_android+//bzlmod_extensions:com_android_dex.bzl%com_android_dex_extension": { "general": { - "bzlTransitiveDigest": "BbM3I4LvjudqQ6/IwaP/LaJXdj2EPfqPleTjiFG4Lg0=", + "bzlTransitiveDigest": "gTuOqknGgqPw9YQSCY+qXxgxVwiLRGdBCsCe4i4q/xw=", "usagesDigest": "c1Y/KGGjUYCyd8zNIVTUh1bynVXRFz6xGKaSCBpQANM=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, + "recordedInputs": [ + "REPO_MAPPING:rules_android+,bazel_tools bazel_tools" + ], "generatedRepoSpecs": { "com_android_dex": { "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", @@ -702,39 +665,30 @@ "build_file": "@@rules_android+//bzlmod_extensions:com_android_dex.BUILD" } } - }, - "recordedRepoMappingEntries": [ - [ - "rules_android+", - "bazel_tools", - "bazel_tools" - ] - ] + } } }, "@@rules_android+//rules/android_sdk_repository:rule.bzl%android_sdk_repository_extension": { "general": { "bzlTransitiveDigest": "+rMrzIrv7sImYmkbXJYv+gFpTJQ79X3MpwwMLI2A+oA=", "usagesDigest": "iEGI2aNDMkHt9LXCdViLNUUOslpiVj2DrevWWXZEFnU=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, + "recordedInputs": [], "generatedRepoSpecs": { "androidsdk": { "repoRuleId": "@@rules_android+//rules/android_sdk_repository:rule.bzl%_android_sdk_repository", "attributes": {} } - }, - "recordedRepoMappingEntries": [] + } } }, "@@rules_python+//python/uv:uv.bzl%uv": { "general": { - "bzlTransitiveDigest": "ijW9KS7qsIY+yBVvJ+Nr1mzwQox09j13DnE3iIwaeTM=", - "usagesDigest": "H8dQoNZcoqP+Mu0tHZTi4KHATzvNkM5ePuEqoQdklIU=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, + "bzlTransitiveDigest": "ELjwPp2kLku5M3S/gpjjVjy3TwT760/zVEQ70nJreHU=", + "usagesDigest": "LCPgc6OYAryd0HQJS9CtnCxvca1YfrjIZ67iPax2aRs=", + "recordedInputs": [ + "REPO_MAPPING:rules_python+,bazel_tools bazel_tools", + "REPO_MAPPING:rules_python+,platforms platforms" + ], "generatedRepoSpecs": { "uv": { "repoRuleId": "@@rules_python+//python/uv/private:uv_toolchains_repo.bzl%uv_toolchains_repo", @@ -754,54 +708,50 @@ "toolchain_target_settings": {} } } - }, - "recordedRepoMappingEntries": [ - [ - "rules_python+", - "bazel_tools", - "bazel_tools" - ], - [ - "rules_python+", - "platforms", - "platforms" - ] - ] + } } }, "@@rules_rust+//crate_universe:extension.bzl%crate": { "general": { - "bzlTransitiveDigest": "sWoZLsB8reEB0HCC26iT6qqYi0StD9vWkRRj4Z4mUPk=", + "bzlTransitiveDigest": "GjMShU79hDI02plU44xzfRpgQ2OiXHF/VLCh0Zs/VQA=", "usagesDigest": "DXwzWBo++525ksMJXODFSlWJmJmVA5TIEvFz8AsPKTg=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": { - "CARGO_BAZEL_DEBUG": null, - "CARGO_BAZEL_GENERATOR_SHA256": null, - "CARGO_BAZEL_GENERATOR_URL": null, - "CARGO_BAZEL_ISOLATED": null, - "CARGO_BAZEL_REPIN": null, - "CARGO_BAZEL_REPIN_ONLY": null, - "CARGO_BAZEL_TIMEOUT": null, - "REPIN": null - }, + "recordedInputs": [ + "ENV:CARGO_BAZEL_DEBUG \\0", + "ENV:CARGO_BAZEL_GENERATOR_SHA256 \\0", + "ENV:CARGO_BAZEL_GENERATOR_URL \\0", + "ENV:CARGO_BAZEL_ISOLATED \\0", + "ENV:CARGO_BAZEL_REPIN \\0", + "ENV:CARGO_BAZEL_REPIN_ONLY \\0", + "ENV:CARGO_BAZEL_TIMEOUT \\0", + "ENV:REPIN \\0", + "REPO_MAPPING:bazel_features+,bazel_features_globals bazel_features++version_extension+bazel_features_globals", + "REPO_MAPPING:bazel_features+,bazel_features_version bazel_features++version_extension+bazel_features_version", + "REPO_MAPPING:rules_cc+,bazel_skylib bazel_skylib+", + "REPO_MAPPING:rules_cc+,bazel_tools bazel_tools", + "REPO_MAPPING:rules_cc+,cc_compatibility_proxy rules_cc++compatibility_proxy+cc_compatibility_proxy", + "REPO_MAPPING:rules_cc+,platforms platforms", + "REPO_MAPPING:rules_cc+,rules_cc rules_cc+", + "REPO_MAPPING:rules_cc++compatibility_proxy+cc_compatibility_proxy,rules_cc rules_cc+", + "REPO_MAPPING:rules_rust+,bazel_features bazel_features+", + "REPO_MAPPING:rules_rust+,bazel_skylib bazel_skylib+", + "REPO_MAPPING:rules_rust+,bazel_tools bazel_tools", + "REPO_MAPPING:rules_rust+,rules_cc rules_cc+", + "REPO_MAPPING:rules_rust+,rules_rust rules_rust+" + ], "generatedRepoSpecs": { "crates": { "repoRuleId": "@@rules_rust+//crate_universe:extensions.bzl%_generate_repo", "attributes": { "contents": { - "BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'protobuf'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files(\n [\n \"cargo-bazel.json\",\n \"crates.bzl\",\n \"defs.bzl\",\n ] + glob(\n allow_empty = True,\n include = [\"*.bazel\"],\n ),\n)\n\nfilegroup(\n name = \"srcs\",\n srcs = glob(\n allow_empty = True,\n include = [\n \"*.bazel\",\n \"*.bzl\",\n ],\n ),\n)\n\n# Workspace Member Dependencies\nalias(\n name = \"googletest-0.14.3\",\n actual = \"@crates__googletest-0.14.3//:googletest\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"googletest\",\n actual = \"@crates__googletest-0.14.3//:googletest\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"linkme-0.3.37\",\n actual = \"@crates__linkme-0.3.37//:linkme\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"linkme\",\n actual = \"@crates__linkme-0.3.37//:linkme\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"paste-1.0.15\",\n actual = \"@crates__paste-1.0.15//:paste\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"paste\",\n actual = \"@crates__paste-1.0.15//:paste\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"quote-1.0.47\",\n actual = \"@crates__quote-1.0.47//:quote\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"quote\",\n actual = \"@crates__quote-1.0.47//:quote\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"syn-3.0.3\",\n actual = \"@crates__syn-3.0.3//:syn\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"syn\",\n actual = \"@crates__syn-3.0.3//:syn\",\n tags = [\"manual\"],\n)\n", + "BUILD.bazel": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'protobuf'\n###############################################################################\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files(\n [\n \"cargo-bazel.json\",\n \"crates.bzl\",\n \"defs.bzl\",\n ] + glob(\n allow_empty = True,\n include = [\"*.bazel\"],\n ),\n)\n\nfilegroup(\n name = \"srcs\",\n srcs = glob(\n allow_empty = True,\n include = [\n \"*.bazel\",\n \"*.bzl\",\n ],\n ),\n)\n\n# Workspace Member Dependencies\nalias(\n name = \"googletest-0.14.3\",\n actual = \"@crates__googletest-0.14.3//:googletest\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"googletest\",\n actual = \"@crates__googletest-0.14.3//:googletest\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"linkme-0.3.37\",\n actual = \"@crates__linkme-0.3.37//:linkme\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"linkme\",\n actual = \"@crates__linkme-0.3.37//:linkme\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"paste-1.0.15\",\n actual = \"@crates__paste-1.0.15//:paste\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"paste\",\n actual = \"@crates__paste-1.0.15//:paste\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"quote-1.0.47\",\n actual = \"@crates__quote-1.0.47//:quote\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"quote\",\n actual = \"@crates__quote-1.0.47//:quote\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"syn-3.0.5\",\n actual = \"@crates__syn-3.0.5//:syn\",\n tags = [\"manual\"],\n)\n\nalias(\n name = \"syn\",\n actual = \"@crates__syn-3.0.5//:syn\",\n tags = [\"manual\"],\n)\n", "alias_rules.bzl": "\"\"\"Alias that transitions its target to `compilation_mode=opt`. Use `transition_alias=\"opt\"` to enable.\"\"\"\n\nload(\"@rules_cc//cc:defs.bzl\", \"CcInfo\")\nload(\"@rules_rust//rust:rust_common.bzl\", \"COMMON_PROVIDERS\")\n\ndef _transition_alias_impl(ctx):\n # `ctx.attr.actual` is a list of 1 item due to the transition\n providers = [ctx.attr.actual[0][provider] for provider in COMMON_PROVIDERS]\n if CcInfo in ctx.attr.actual[0]:\n providers.append(ctx.attr.actual[0][CcInfo])\n return providers\n\ndef _change_compilation_mode(compilation_mode):\n def _change_compilation_mode_impl(_settings, _attr):\n return {\n \"//command_line_option:compilation_mode\": compilation_mode,\n }\n\n return transition(\n implementation = _change_compilation_mode_impl,\n inputs = [],\n outputs = [\n \"//command_line_option:compilation_mode\",\n ],\n )\n\ndef _transition_alias_rule(compilation_mode):\n return rule(\n implementation = _transition_alias_impl,\n provides = COMMON_PROVIDERS,\n attrs = {\n \"actual\": attr.label(\n mandatory = True,\n doc = \"`rust_library()` target to transition to `compilation_mode=opt`.\",\n providers = COMMON_PROVIDERS,\n cfg = _change_compilation_mode(compilation_mode),\n ),\n \"_allowlist_function_transition\": attr.label(\n default = \"@bazel_tools//tools/allowlists/function_transition_allowlist\",\n ),\n },\n doc = \"Transitions a Rust library crate to the `compilation_mode=opt`.\",\n )\n\ntransition_alias_dbg = _transition_alias_rule(\"dbg\")\ntransition_alias_fastbuild = _transition_alias_rule(\"fastbuild\")\ntransition_alias_opt = _transition_alias_rule(\"opt\")\n", - "defs.bzl": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'protobuf'\n###############################################################################\n\"\"\"\n# `crates_repository` API\n\n- [aliases](#aliases)\n- [crate_deps](#crate_deps)\n- [all_crate_deps](#all_crate_deps)\n- [crate_repositories](#crate_repositories)\n\n\"\"\"\n\nload(\"@bazel_tools//tools/build_defs/repo:git.bzl\", \"new_git_repository\")\nload(\"@bazel_tools//tools/build_defs/repo:http.bzl\", \"http_archive\")\nload(\"@bazel_tools//tools/build_defs/repo:utils.bzl\", \"maybe\")\nload(\"@bazel_skylib//lib:selects.bzl\", \"selects\")\nload(\"@rules_rust//crate_universe/private:local_crate_mirror.bzl\", \"local_crate_mirror\")\n\n###############################################################################\n# MACROS API\n###############################################################################\n\n# An identifier that represent common dependencies (unconditional).\n_COMMON_CONDITION = \"\"\n\ndef _flatten_dependency_maps(all_dependency_maps):\n \"\"\"Flatten a list of dependency maps into one dictionary.\n\n Dependency maps have the following structure:\n\n ```python\n DEPENDENCIES_MAP = {\n # The first key in the map is a Bazel package\n # name of the workspace this file is defined in.\n \"workspace_member_package\": {\n\n # Not all dependencies are supported for all platforms.\n # the condition key is the condition required to be true\n # on the host platform.\n \"condition\": {\n\n # An alias to a crate target. # The label of the crate target the\n # Aliases are only crate names. # package name refers to.\n \"package_name\": \"@full//:label\",\n }\n }\n }\n ```\n\n Args:\n all_dependency_maps (list): A list of dicts as described above\n\n Returns:\n dict: A dictionary as described above\n \"\"\"\n dependencies = {}\n\n for workspace_deps_map in all_dependency_maps:\n for pkg_name, conditional_deps_map in workspace_deps_map.items():\n if pkg_name not in dependencies:\n non_frozen_map = dict()\n for key, values in conditional_deps_map.items():\n non_frozen_map.update({key: dict(values.items())})\n dependencies.setdefault(pkg_name, non_frozen_map)\n continue\n\n for condition, deps_map in conditional_deps_map.items():\n # If the condition has not been recorded, do so and continue\n if condition not in dependencies[pkg_name]:\n dependencies[pkg_name].setdefault(condition, dict(deps_map.items()))\n continue\n\n # Alert on any miss-matched dependencies\n inconsistent_entries = []\n for crate_name, crate_label in deps_map.items():\n existing = dependencies[pkg_name][condition].get(crate_name)\n if existing and existing != crate_label:\n inconsistent_entries.append((crate_name, existing, crate_label))\n dependencies[pkg_name][condition].update({crate_name: crate_label})\n\n return dependencies\n\ndef crate_deps(deps, package_name = None):\n \"\"\"Finds the fully qualified label of the requested crates for the package where this macro is called.\n\n Args:\n deps (list): The desired list of crate targets.\n package_name (str, optional): The package name of the set of dependencies to look up.\n Defaults to `native.package_name()`.\n\n Returns:\n list: A list of labels to generated rust targets (str)\n \"\"\"\n\n if not deps:\n return []\n\n if package_name == None:\n package_name = native.package_name()\n\n # Join both sets of dependencies\n dependencies = _flatten_dependency_maps([\n _NORMAL_DEPENDENCIES,\n _NORMAL_DEV_DEPENDENCIES,\n _PROC_MACRO_DEPENDENCIES,\n _PROC_MACRO_DEV_DEPENDENCIES,\n _BUILD_DEPENDENCIES,\n _BUILD_PROC_MACRO_DEPENDENCIES,\n ]).pop(package_name, {})\n\n # Combine all conditional packages so we can easily index over a flat list\n # TODO: Perhaps this should actually return select statements and maintain\n # the conditionals of the dependencies\n flat_deps = {}\n for deps_set in dependencies.values():\n for crate_name, crate_label in deps_set.items():\n flat_deps.update({crate_name: crate_label})\n\n missing_crates = []\n crate_targets = []\n for crate_target in deps:\n if crate_target not in flat_deps:\n missing_crates.append(crate_target)\n else:\n crate_targets.append(flat_deps[crate_target])\n\n if missing_crates:\n fail(\"Could not find crates `{}` among dependencies of `{}`. Available dependencies were `{}`\".format(\n missing_crates,\n package_name,\n dependencies,\n ))\n\n return crate_targets\n\ndef all_crate_deps(\n normal = False, \n normal_dev = False, \n proc_macro = False, \n proc_macro_dev = False,\n build = False,\n build_proc_macro = False,\n package_name = None):\n \"\"\"Finds the fully qualified label of all requested direct crate dependencies \\\n for the package where this macro is called.\n\n If no parameters are set, all normal dependencies are returned. Setting any one flag will\n otherwise impact the contents of the returned list.\n\n Args:\n normal (bool, optional): If True, normal dependencies are included in the\n output list.\n normal_dev (bool, optional): If True, normal dev dependencies will be\n included in the output list.\n proc_macro (bool, optional): If True, proc_macro dependencies are included\n in the output list.\n proc_macro_dev (bool, optional): If True, dev proc_macro dependencies are\n included in the output list.\n build (bool, optional): If True, build dependencies are included\n in the output list.\n build_proc_macro (bool, optional): If True, build proc_macro dependencies are\n included in the output list.\n package_name (str, optional): The package name of the set of dependencies to look up.\n Defaults to `native.package_name()` when unset.\n\n Returns:\n list: A list of labels to generated rust targets (str)\n \"\"\"\n\n if package_name == None:\n package_name = native.package_name()\n\n # Determine the relevant maps to use\n all_dependency_maps = []\n if normal:\n all_dependency_maps.append(_NORMAL_DEPENDENCIES)\n if normal_dev:\n all_dependency_maps.append(_NORMAL_DEV_DEPENDENCIES)\n if proc_macro:\n all_dependency_maps.append(_PROC_MACRO_DEPENDENCIES)\n if proc_macro_dev:\n all_dependency_maps.append(_PROC_MACRO_DEV_DEPENDENCIES)\n if build:\n all_dependency_maps.append(_BUILD_DEPENDENCIES)\n if build_proc_macro:\n all_dependency_maps.append(_BUILD_PROC_MACRO_DEPENDENCIES)\n\n # Default to always using normal dependencies\n if not all_dependency_maps:\n all_dependency_maps.append(_NORMAL_DEPENDENCIES)\n\n dependencies = _flatten_dependency_maps(all_dependency_maps).pop(package_name, None)\n\n if not dependencies:\n if dependencies == None:\n fail(\"Tried to get all_crate_deps for package \" + package_name + \" but that package had no Cargo.toml file\")\n else:\n return []\n\n crate_deps = list(dependencies.pop(_COMMON_CONDITION, {}).values())\n for condition, deps in dependencies.items():\n crate_deps += selects.with_or({\n tuple(_CONDITIONS[condition]): deps.values(),\n \"//conditions:default\": [],\n })\n\n return crate_deps\n\ndef aliases(\n normal = False,\n normal_dev = False,\n proc_macro = False,\n proc_macro_dev = False,\n build = False,\n build_proc_macro = False,\n package_name = None):\n \"\"\"Produces a map of Crate alias names to their original label\n\n If no dependency kinds are specified, `normal` and `proc_macro` are used by default.\n Setting any one flag will otherwise determine the contents of the returned dict.\n\n Args:\n normal (bool, optional): If True, normal dependencies are included in the\n output list.\n normal_dev (bool, optional): If True, normal dev dependencies will be\n included in the output list..\n proc_macro (bool, optional): If True, proc_macro dependencies are included\n in the output list.\n proc_macro_dev (bool, optional): If True, dev proc_macro dependencies are\n included in the output list.\n build (bool, optional): If True, build dependencies are included\n in the output list.\n build_proc_macro (bool, optional): If True, build proc_macro dependencies are\n included in the output list.\n package_name (str, optional): The package name of the set of dependencies to look up.\n Defaults to `native.package_name()` when unset.\n\n Returns:\n dict: The aliases of all associated packages\n \"\"\"\n if package_name == None:\n package_name = native.package_name()\n\n # Determine the relevant maps to use\n all_aliases_maps = []\n if normal:\n all_aliases_maps.append(_NORMAL_ALIASES)\n if normal_dev:\n all_aliases_maps.append(_NORMAL_DEV_ALIASES)\n if proc_macro:\n all_aliases_maps.append(_PROC_MACRO_ALIASES)\n if proc_macro_dev:\n all_aliases_maps.append(_PROC_MACRO_DEV_ALIASES)\n if build:\n all_aliases_maps.append(_BUILD_ALIASES)\n if build_proc_macro:\n all_aliases_maps.append(_BUILD_PROC_MACRO_ALIASES)\n\n # Default to always using normal aliases\n if not all_aliases_maps:\n all_aliases_maps.append(_NORMAL_ALIASES)\n all_aliases_maps.append(_PROC_MACRO_ALIASES)\n\n aliases = _flatten_dependency_maps(all_aliases_maps).pop(package_name, None)\n\n if not aliases:\n return dict()\n\n common_items = aliases.pop(_COMMON_CONDITION, {}).items()\n\n # If there are only common items in the dictionary, immediately return them\n if not len(aliases.keys()) == 1:\n return dict(common_items)\n\n # Build a single select statement where each conditional has accounted for the\n # common set of aliases.\n crate_aliases = {\"//conditions:default\": dict(common_items)}\n for condition, deps in aliases.items():\n condition_triples = _CONDITIONS[condition]\n for triple in condition_triples:\n if triple in crate_aliases:\n crate_aliases[triple].update(deps)\n else:\n crate_aliases.update({triple: dict(deps.items() + common_items)})\n\n return select(crate_aliases)\n\n###############################################################################\n# WORKSPACE MEMBER DEPS AND ALIASES\n###############################################################################\n\n_NORMAL_DEPENDENCIES = {\n \"\": {\n _COMMON_CONDITION: {\n \"googletest\": Label(\"@crates//:googletest-0.14.3\"),\n \"linkme\": Label(\"@crates//:linkme-0.3.37\"),\n \"quote\": Label(\"@crates//:quote-1.0.47\"),\n \"syn\": Label(\"@crates//:syn-3.0.3\"),\n },\n },\n}\n\n\n_NORMAL_ALIASES = {\n \"\": {\n _COMMON_CONDITION: {\n },\n },\n}\n\n\n_NORMAL_DEV_DEPENDENCIES = {\n \"\": {\n },\n}\n\n\n_NORMAL_DEV_ALIASES = {\n \"\": {\n },\n}\n\n\n_PROC_MACRO_DEPENDENCIES = {\n \"\": {\n _COMMON_CONDITION: {\n \"paste\": Label(\"@crates//:paste-1.0.15\"),\n },\n },\n}\n\n\n_PROC_MACRO_ALIASES = {\n \"\": {\n },\n}\n\n\n_PROC_MACRO_DEV_DEPENDENCIES = {\n \"\": {\n },\n}\n\n\n_PROC_MACRO_DEV_ALIASES = {\n \"\": {\n },\n}\n\n\n_BUILD_DEPENDENCIES = {\n \"\": {\n },\n}\n\n\n_BUILD_ALIASES = {\n \"\": {\n },\n}\n\n\n_BUILD_PROC_MACRO_DEPENDENCIES = {\n \"\": {\n },\n}\n\n\n_BUILD_PROC_MACRO_ALIASES = {\n \"\": {\n },\n}\n\n\n_CONDITIONS = {\n \"aarch64-apple-darwin\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\"],\n \"aarch64-unknown-linux-gnu\": [\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\"],\n \"wasm32-unknown-unknown\": [\"@rules_rust//rust/platform:wasm32-unknown-unknown\"],\n \"wasm32-wasip1\": [\"@rules_rust//rust/platform:wasm32-wasip1\"],\n \"x86_64-pc-windows-msvc\": [\"@rules_rust//rust/platform:x86_64-pc-windows-msvc\"],\n \"x86_64-unknown-linux-gnu\": [\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"x86_64-unknown-nixos-gnu\": [\"@rules_rust//rust/platform:x86_64-unknown-nixos-gnu\"],\n}\n\n###############################################################################\n\ndef crate_repositories():\n \"\"\"A macro for defining repositories for all generated crates.\n\n Returns:\n A list of repos visible to the module through the module extension.\n \"\"\"\n maybe(\n http_archive,\n name = \"crates__aho-corasick-1.1.5\",\n sha256 = \"c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/aho-corasick/1.1.5/download\"],\n strip_prefix = \"aho-corasick-1.1.5\",\n build_file = Label(\"@crates//crates:BUILD.aho-corasick-1.1.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"crates__autocfg-1.5.1\",\n sha256 = \"f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/autocfg/1.5.1/download\"],\n strip_prefix = \"autocfg-1.5.1\",\n build_file = Label(\"@crates//crates:BUILD.autocfg-1.5.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"crates__googletest-0.14.3\",\n sha256 = \"f6b5e2f2b556b7b90297a5a35c8267dd43a537923d2b329beefdba2b4ec19d94\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/googletest/0.14.3/download\"],\n strip_prefix = \"googletest-0.14.3\",\n build_file = Label(\"@crates//crates:BUILD.googletest-0.14.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"crates__googletest_macro-0.14.3\",\n sha256 = \"2ae6abc96141edd26bf5aeec0f119c129c44de3ced09e5073711a02cb74725d0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/googletest_macro/0.14.3/download\"],\n strip_prefix = \"googletest_macro-0.14.3\",\n build_file = Label(\"@crates//crates:BUILD.googletest_macro-0.14.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"crates__linkme-0.3.37\",\n sha256 = \"3045e122bd98aef8ec3ad58ce84f0791f64e70163d1a02710af4aa11a4d54cc5\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/linkme/0.3.37/download\"],\n strip_prefix = \"linkme-0.3.37\",\n build_file = Label(\"@crates//crates:BUILD.linkme-0.3.37.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"crates__linkme-impl-0.3.37\",\n sha256 = \"77060ebe535362c3da75682cd17b0431017b6e7c5661e714fc69a7ad017d1301\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/linkme-impl/0.3.37/download\"],\n strip_prefix = \"linkme-impl-0.3.37\",\n build_file = Label(\"@crates//crates:BUILD.linkme-impl-0.3.37.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"crates__memchr-2.8.3\",\n sha256 = \"cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/memchr/2.8.3/download\"],\n strip_prefix = \"memchr-2.8.3\",\n build_file = Label(\"@crates//crates:BUILD.memchr-2.8.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"crates__num-traits-0.2.19\",\n sha256 = \"071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/num-traits/0.2.19/download\"],\n strip_prefix = \"num-traits-0.2.19\",\n build_file = Label(\"@crates//crates:BUILD.num-traits-0.2.19.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"crates__paste-1.0.15\",\n sha256 = \"57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/paste/1.0.15/download\"],\n strip_prefix = \"paste-1.0.15\",\n build_file = Label(\"@crates//crates:BUILD.paste-1.0.15.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"crates__proc-macro2-1.0.107\",\n sha256 = \"985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/proc-macro2/1.0.107/download\"],\n strip_prefix = \"proc-macro2-1.0.107\",\n build_file = Label(\"@crates//crates:BUILD.proc-macro2-1.0.107.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"crates__quote-1.0.47\",\n sha256 = \"1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/quote/1.0.47/download\"],\n strip_prefix = \"quote-1.0.47\",\n build_file = Label(\"@crates//crates:BUILD.quote-1.0.47.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"crates__regex-1.13.1\",\n sha256 = \"f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/regex/1.13.1/download\"],\n strip_prefix = \"regex-1.13.1\",\n build_file = Label(\"@crates//crates:BUILD.regex-1.13.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"crates__regex-automata-0.4.18\",\n sha256 = \"ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/regex-automata/0.4.18/download\"],\n strip_prefix = \"regex-automata-0.4.18\",\n build_file = Label(\"@crates//crates:BUILD.regex-automata-0.4.18.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"crates__regex-syntax-0.8.11\",\n sha256 = \"d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/regex-syntax/0.8.11/download\"],\n strip_prefix = \"regex-syntax-0.8.11\",\n build_file = Label(\"@crates//crates:BUILD.regex-syntax-0.8.11.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"crates__rustversion-1.0.23\",\n sha256 = \"cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rustversion/1.0.23/download\"],\n strip_prefix = \"rustversion-1.0.23\",\n build_file = Label(\"@crates//crates:BUILD.rustversion-1.0.23.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"crates__syn-2.0.119\",\n sha256 = \"872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/syn/2.0.119/download\"],\n strip_prefix = \"syn-2.0.119\",\n build_file = Label(\"@crates//crates:BUILD.syn-2.0.119.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"crates__syn-3.0.3\",\n sha256 = \"53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/syn/3.0.3/download\"],\n strip_prefix = \"syn-3.0.3\",\n build_file = Label(\"@crates//crates:BUILD.syn-3.0.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"crates__unicode-ident-1.0.24\",\n sha256 = \"e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/unicode-ident/1.0.24/download\"],\n strip_prefix = \"unicode-ident-1.0.24\",\n build_file = Label(\"@crates//crates:BUILD.unicode-ident-1.0.24.bazel\"),\n )\n\n return [\n struct(repo=\"crates__googletest-0.14.3\", is_dev_dep = False),\n struct(repo=\"crates__linkme-0.3.37\", is_dev_dep = False),\n struct(repo=\"crates__paste-1.0.15\", is_dev_dep = False),\n struct(repo=\"crates__quote-1.0.47\", is_dev_dep = False),\n struct(repo=\"crates__syn-3.0.3\", is_dev_dep = False),\n ]\n" + "defs.bzl": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'protobuf'\n###############################################################################\n\"\"\"\n# `crates_repository` API\n\n- [aliases](#aliases)\n- [crate_deps](#crate_deps)\n- [all_crate_deps](#all_crate_deps)\n- [crate_repositories](#crate_repositories)\n\n\"\"\"\n\nload(\"@bazel_tools//tools/build_defs/repo:git.bzl\", \"new_git_repository\")\nload(\"@bazel_tools//tools/build_defs/repo:http.bzl\", \"http_archive\")\nload(\"@bazel_tools//tools/build_defs/repo:utils.bzl\", \"maybe\")\nload(\"@bazel_skylib//lib:selects.bzl\", \"selects\")\nload(\"@rules_rust//crate_universe/private:local_crate_mirror.bzl\", \"local_crate_mirror\")\n\n###############################################################################\n# MACROS API\n###############################################################################\n\n# An identifier that represent common dependencies (unconditional).\n_COMMON_CONDITION = \"\"\n\ndef _flatten_dependency_maps(all_dependency_maps):\n \"\"\"Flatten a list of dependency maps into one dictionary.\n\n Dependency maps have the following structure:\n\n ```python\n DEPENDENCIES_MAP = {\n # The first key in the map is a Bazel package\n # name of the workspace this file is defined in.\n \"workspace_member_package\": {\n\n # Not all dependencies are supported for all platforms.\n # the condition key is the condition required to be true\n # on the host platform.\n \"condition\": {\n\n # An alias to a crate target. # The label of the crate target the\n # Aliases are only crate names. # package name refers to.\n \"package_name\": \"@full//:label\",\n }\n }\n }\n ```\n\n Args:\n all_dependency_maps (list): A list of dicts as described above\n\n Returns:\n dict: A dictionary as described above\n \"\"\"\n dependencies = {}\n\n for workspace_deps_map in all_dependency_maps:\n for pkg_name, conditional_deps_map in workspace_deps_map.items():\n if pkg_name not in dependencies:\n non_frozen_map = dict()\n for key, values in conditional_deps_map.items():\n non_frozen_map.update({key: dict(values.items())})\n dependencies.setdefault(pkg_name, non_frozen_map)\n continue\n\n for condition, deps_map in conditional_deps_map.items():\n # If the condition has not been recorded, do so and continue\n if condition not in dependencies[pkg_name]:\n dependencies[pkg_name].setdefault(condition, dict(deps_map.items()))\n continue\n\n # Alert on any miss-matched dependencies\n inconsistent_entries = []\n for crate_name, crate_label in deps_map.items():\n existing = dependencies[pkg_name][condition].get(crate_name)\n if existing and existing != crate_label:\n inconsistent_entries.append((crate_name, existing, crate_label))\n dependencies[pkg_name][condition].update({crate_name: crate_label})\n\n return dependencies\n\ndef crate_deps(deps, package_name = None):\n \"\"\"Finds the fully qualified label of the requested crates for the package where this macro is called.\n\n Args:\n deps (list): The desired list of crate targets.\n package_name (str, optional): The package name of the set of dependencies to look up.\n Defaults to `native.package_name()`.\n\n Returns:\n list: A list of labels to generated rust targets (str)\n \"\"\"\n\n if not deps:\n return []\n\n if package_name == None:\n package_name = native.package_name()\n\n # Join both sets of dependencies\n dependencies = _flatten_dependency_maps([\n _NORMAL_DEPENDENCIES,\n _NORMAL_DEV_DEPENDENCIES,\n _PROC_MACRO_DEPENDENCIES,\n _PROC_MACRO_DEV_DEPENDENCIES,\n _BUILD_DEPENDENCIES,\n _BUILD_PROC_MACRO_DEPENDENCIES,\n ]).pop(package_name, {})\n\n # Combine all conditional packages so we can easily index over a flat list\n # TODO: Perhaps this should actually return select statements and maintain\n # the conditionals of the dependencies\n flat_deps = {}\n for deps_set in dependencies.values():\n for crate_name, crate_label in deps_set.items():\n flat_deps.update({crate_name: crate_label})\n\n missing_crates = []\n crate_targets = []\n for crate_target in deps:\n if crate_target not in flat_deps:\n missing_crates.append(crate_target)\n else:\n crate_targets.append(flat_deps[crate_target])\n\n if missing_crates:\n fail(\"Could not find crates `{}` among dependencies of `{}`. Available dependencies were `{}`\".format(\n missing_crates,\n package_name,\n dependencies,\n ))\n\n return crate_targets\n\ndef all_crate_deps(\n normal = False, \n normal_dev = False, \n proc_macro = False, \n proc_macro_dev = False,\n build = False,\n build_proc_macro = False,\n package_name = None):\n \"\"\"Finds the fully qualified label of all requested direct crate dependencies \\\n for the package where this macro is called.\n\n If no parameters are set, all normal dependencies are returned. Setting any one flag will\n otherwise impact the contents of the returned list.\n\n Args:\n normal (bool, optional): If True, normal dependencies are included in the\n output list.\n normal_dev (bool, optional): If True, normal dev dependencies will be\n included in the output list.\n proc_macro (bool, optional): If True, proc_macro dependencies are included\n in the output list.\n proc_macro_dev (bool, optional): If True, dev proc_macro dependencies are\n included in the output list.\n build (bool, optional): If True, build dependencies are included\n in the output list.\n build_proc_macro (bool, optional): If True, build proc_macro dependencies are\n included in the output list.\n package_name (str, optional): The package name of the set of dependencies to look up.\n Defaults to `native.package_name()` when unset.\n\n Returns:\n list: A list of labels to generated rust targets (str)\n \"\"\"\n\n if package_name == None:\n package_name = native.package_name()\n\n # Determine the relevant maps to use\n all_dependency_maps = []\n if normal:\n all_dependency_maps.append(_NORMAL_DEPENDENCIES)\n if normal_dev:\n all_dependency_maps.append(_NORMAL_DEV_DEPENDENCIES)\n if proc_macro:\n all_dependency_maps.append(_PROC_MACRO_DEPENDENCIES)\n if proc_macro_dev:\n all_dependency_maps.append(_PROC_MACRO_DEV_DEPENDENCIES)\n if build:\n all_dependency_maps.append(_BUILD_DEPENDENCIES)\n if build_proc_macro:\n all_dependency_maps.append(_BUILD_PROC_MACRO_DEPENDENCIES)\n\n # Default to always using normal dependencies\n if not all_dependency_maps:\n all_dependency_maps.append(_NORMAL_DEPENDENCIES)\n\n dependencies = _flatten_dependency_maps(all_dependency_maps).pop(package_name, None)\n\n if not dependencies:\n if dependencies == None:\n fail(\"Tried to get all_crate_deps for package \" + package_name + \" but that package had no Cargo.toml file\")\n else:\n return []\n\n crate_deps = list(dependencies.pop(_COMMON_CONDITION, {}).values())\n for condition, deps in dependencies.items():\n crate_deps += selects.with_or({\n tuple(_CONDITIONS[condition]): deps.values(),\n \"//conditions:default\": [],\n })\n\n return crate_deps\n\ndef aliases(\n normal = False,\n normal_dev = False,\n proc_macro = False,\n proc_macro_dev = False,\n build = False,\n build_proc_macro = False,\n package_name = None):\n \"\"\"Produces a map of Crate alias names to their original label\n\n If no dependency kinds are specified, `normal` and `proc_macro` are used by default.\n Setting any one flag will otherwise determine the contents of the returned dict.\n\n Args:\n normal (bool, optional): If True, normal dependencies are included in the\n output list.\n normal_dev (bool, optional): If True, normal dev dependencies will be\n included in the output list..\n proc_macro (bool, optional): If True, proc_macro dependencies are included\n in the output list.\n proc_macro_dev (bool, optional): If True, dev proc_macro dependencies are\n included in the output list.\n build (bool, optional): If True, build dependencies are included\n in the output list.\n build_proc_macro (bool, optional): If True, build proc_macro dependencies are\n included in the output list.\n package_name (str, optional): The package name of the set of dependencies to look up.\n Defaults to `native.package_name()` when unset.\n\n Returns:\n dict: The aliases of all associated packages\n \"\"\"\n if package_name == None:\n package_name = native.package_name()\n\n # Determine the relevant maps to use\n all_aliases_maps = []\n if normal:\n all_aliases_maps.append(_NORMAL_ALIASES)\n if normal_dev:\n all_aliases_maps.append(_NORMAL_DEV_ALIASES)\n if proc_macro:\n all_aliases_maps.append(_PROC_MACRO_ALIASES)\n if proc_macro_dev:\n all_aliases_maps.append(_PROC_MACRO_DEV_ALIASES)\n if build:\n all_aliases_maps.append(_BUILD_ALIASES)\n if build_proc_macro:\n all_aliases_maps.append(_BUILD_PROC_MACRO_ALIASES)\n\n # Default to always using normal aliases\n if not all_aliases_maps:\n all_aliases_maps.append(_NORMAL_ALIASES)\n all_aliases_maps.append(_PROC_MACRO_ALIASES)\n\n aliases = _flatten_dependency_maps(all_aliases_maps).pop(package_name, None)\n\n if not aliases:\n return dict()\n\n common_items = aliases.pop(_COMMON_CONDITION, {}).items()\n\n # If there are only common items in the dictionary, immediately return them\n if not len(aliases.keys()) == 1:\n return dict(common_items)\n\n # Build a single select statement where each conditional has accounted for the\n # common set of aliases.\n crate_aliases = {\"//conditions:default\": dict(common_items)}\n for condition, deps in aliases.items():\n condition_triples = _CONDITIONS[condition]\n for triple in condition_triples:\n if triple in crate_aliases:\n crate_aliases[triple].update(deps)\n else:\n crate_aliases.update({triple: dict(deps.items() + common_items)})\n\n return select(crate_aliases)\n\n###############################################################################\n# WORKSPACE MEMBER DEPS AND ALIASES\n###############################################################################\n\n_NORMAL_DEPENDENCIES = {\n \"\": {\n _COMMON_CONDITION: {\n \"googletest\": Label(\"@crates//:googletest-0.14.3\"),\n \"linkme\": Label(\"@crates//:linkme-0.3.37\"),\n \"quote\": Label(\"@crates//:quote-1.0.47\"),\n \"syn\": Label(\"@crates//:syn-3.0.5\"),\n },\n },\n}\n\n\n_NORMAL_ALIASES = {\n \"\": {\n _COMMON_CONDITION: {\n },\n },\n}\n\n\n_NORMAL_DEV_DEPENDENCIES = {\n \"\": {\n },\n}\n\n\n_NORMAL_DEV_ALIASES = {\n \"\": {\n },\n}\n\n\n_PROC_MACRO_DEPENDENCIES = {\n \"\": {\n _COMMON_CONDITION: {\n \"paste\": Label(\"@crates//:paste-1.0.15\"),\n },\n },\n}\n\n\n_PROC_MACRO_ALIASES = {\n \"\": {\n },\n}\n\n\n_PROC_MACRO_DEV_DEPENDENCIES = {\n \"\": {\n },\n}\n\n\n_PROC_MACRO_DEV_ALIASES = {\n \"\": {\n },\n}\n\n\n_BUILD_DEPENDENCIES = {\n \"\": {\n },\n}\n\n\n_BUILD_ALIASES = {\n \"\": {\n },\n}\n\n\n_BUILD_PROC_MACRO_DEPENDENCIES = {\n \"\": {\n },\n}\n\n\n_BUILD_PROC_MACRO_ALIASES = {\n \"\": {\n },\n}\n\n\n_CONDITIONS = {\n \"aarch64-apple-darwin\": [\"@rules_rust//rust/platform:aarch64-apple-darwin\"],\n \"aarch64-unknown-linux-gnu\": [\"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\"],\n \"wasm32-unknown-unknown\": [\"@rules_rust//rust/platform:wasm32-unknown-unknown\"],\n \"wasm32-wasip1\": [\"@rules_rust//rust/platform:wasm32-wasip1\"],\n \"x86_64-pc-windows-msvc\": [\"@rules_rust//rust/platform:x86_64-pc-windows-msvc\"],\n \"x86_64-unknown-linux-gnu\": [\"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\"],\n \"x86_64-unknown-nixos-gnu\": [\"@rules_rust//rust/platform:x86_64-unknown-nixos-gnu\"],\n}\n\n###############################################################################\n\ndef crate_repositories():\n \"\"\"A macro for defining repositories for all generated crates.\n\n Returns:\n A list of repos visible to the module through the module extension.\n \"\"\"\n maybe(\n http_archive,\n name = \"crates__aho-corasick-1.1.5\",\n sha256 = \"c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/aho-corasick/1.1.5/download\"],\n strip_prefix = \"aho-corasick-1.1.5\",\n build_file = Label(\"@crates//crates:BUILD.aho-corasick-1.1.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"crates__autocfg-1.5.1\",\n sha256 = \"f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/autocfg/1.5.1/download\"],\n strip_prefix = \"autocfg-1.5.1\",\n build_file = Label(\"@crates//crates:BUILD.autocfg-1.5.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"crates__googletest-0.14.3\",\n sha256 = \"f6b5e2f2b556b7b90297a5a35c8267dd43a537923d2b329beefdba2b4ec19d94\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/googletest/0.14.3/download\"],\n strip_prefix = \"googletest-0.14.3\",\n build_file = Label(\"@crates//crates:BUILD.googletest-0.14.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"crates__googletest_macro-0.14.3\",\n sha256 = \"2ae6abc96141edd26bf5aeec0f119c129c44de3ced09e5073711a02cb74725d0\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/googletest_macro/0.14.3/download\"],\n strip_prefix = \"googletest_macro-0.14.3\",\n build_file = Label(\"@crates//crates:BUILD.googletest_macro-0.14.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"crates__linkme-0.3.37\",\n sha256 = \"3045e122bd98aef8ec3ad58ce84f0791f64e70163d1a02710af4aa11a4d54cc5\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/linkme/0.3.37/download\"],\n strip_prefix = \"linkme-0.3.37\",\n build_file = Label(\"@crates//crates:BUILD.linkme-0.3.37.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"crates__linkme-impl-0.3.37\",\n sha256 = \"77060ebe535362c3da75682cd17b0431017b6e7c5661e714fc69a7ad017d1301\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/linkme-impl/0.3.37/download\"],\n strip_prefix = \"linkme-impl-0.3.37\",\n build_file = Label(\"@crates//crates:BUILD.linkme-impl-0.3.37.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"crates__memchr-2.8.3\",\n sha256 = \"cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/memchr/2.8.3/download\"],\n strip_prefix = \"memchr-2.8.3\",\n build_file = Label(\"@crates//crates:BUILD.memchr-2.8.3.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"crates__num-traits-0.2.19\",\n sha256 = \"071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/num-traits/0.2.19/download\"],\n strip_prefix = \"num-traits-0.2.19\",\n build_file = Label(\"@crates//crates:BUILD.num-traits-0.2.19.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"crates__paste-1.0.15\",\n sha256 = \"57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/paste/1.0.15/download\"],\n strip_prefix = \"paste-1.0.15\",\n build_file = Label(\"@crates//crates:BUILD.paste-1.0.15.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"crates__proc-macro2-1.0.107\",\n sha256 = \"985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/proc-macro2/1.0.107/download\"],\n strip_prefix = \"proc-macro2-1.0.107\",\n build_file = Label(\"@crates//crates:BUILD.proc-macro2-1.0.107.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"crates__quote-1.0.47\",\n sha256 = \"1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/quote/1.0.47/download\"],\n strip_prefix = \"quote-1.0.47\",\n build_file = Label(\"@crates//crates:BUILD.quote-1.0.47.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"crates__regex-1.13.1\",\n sha256 = \"f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/regex/1.13.1/download\"],\n strip_prefix = \"regex-1.13.1\",\n build_file = Label(\"@crates//crates:BUILD.regex-1.13.1.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"crates__regex-automata-0.4.18\",\n sha256 = \"ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/regex-automata/0.4.18/download\"],\n strip_prefix = \"regex-automata-0.4.18\",\n build_file = Label(\"@crates//crates:BUILD.regex-automata-0.4.18.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"crates__regex-syntax-0.8.11\",\n sha256 = \"d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/regex-syntax/0.8.11/download\"],\n strip_prefix = \"regex-syntax-0.8.11\",\n build_file = Label(\"@crates//crates:BUILD.regex-syntax-0.8.11.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"crates__rustversion-1.0.23\",\n sha256 = \"cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/rustversion/1.0.23/download\"],\n strip_prefix = \"rustversion-1.0.23\",\n build_file = Label(\"@crates//crates:BUILD.rustversion-1.0.23.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"crates__syn-2.0.119\",\n sha256 = \"872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/syn/2.0.119/download\"],\n strip_prefix = \"syn-2.0.119\",\n build_file = Label(\"@crates//crates:BUILD.syn-2.0.119.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"crates__syn-3.0.5\",\n sha256 = \"12df2e0110f65b775f769bb17ef989067a1d931b2eb822bd4346631eeada89f9\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/syn/3.0.5/download\"],\n strip_prefix = \"syn-3.0.5\",\n build_file = Label(\"@crates//crates:BUILD.syn-3.0.5.bazel\"),\n )\n\n maybe(\n http_archive,\n name = \"crates__unicode-ident-1.0.24\",\n sha256 = \"e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75\",\n type = \"tar.gz\",\n urls = [\"https://static.crates.io/crates/unicode-ident/1.0.24/download\"],\n strip_prefix = \"unicode-ident-1.0.24\",\n build_file = Label(\"@crates//crates:BUILD.unicode-ident-1.0.24.bazel\"),\n )\n\n return [\n struct(repo=\"crates__googletest-0.14.3\", is_dev_dep = False),\n struct(repo=\"crates__linkme-0.3.37\", is_dev_dep = False),\n struct(repo=\"crates__paste-1.0.15\", is_dev_dep = False),\n struct(repo=\"crates__quote-1.0.47\", is_dev_dep = False),\n struct(repo=\"crates__syn-3.0.5\", is_dev_dep = False),\n ]\n" } } }, "crates__aho-corasick-1.1.5": { "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "patch_args": [], - "patch_tool": "", - "patches": [], "remote_patch_strip": 1, "sha256": "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba", "type": "tar.gz", @@ -815,9 +765,6 @@ "crates__autocfg-1.5.1": { "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "patch_args": [], - "patch_tool": "", - "patches": [], "remote_patch_strip": 1, "sha256": "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53", "type": "tar.gz", @@ -831,9 +778,6 @@ "crates__googletest-0.14.3": { "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "patch_args": [], - "patch_tool": "", - "patches": [], "remote_patch_strip": 1, "sha256": "f6b5e2f2b556b7b90297a5a35c8267dd43a537923d2b329beefdba2b4ec19d94", "type": "tar.gz", @@ -847,9 +791,6 @@ "crates__googletest_macro-0.14.3": { "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "patch_args": [], - "patch_tool": "", - "patches": [], "remote_patch_strip": 1, "sha256": "2ae6abc96141edd26bf5aeec0f119c129c44de3ced09e5073711a02cb74725d0", "type": "tar.gz", @@ -863,9 +804,6 @@ "crates__linkme-0.3.37": { "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "patch_args": [], - "patch_tool": "", - "patches": [], "remote_patch_strip": 1, "sha256": "3045e122bd98aef8ec3ad58ce84f0791f64e70163d1a02710af4aa11a4d54cc5", "type": "tar.gz", @@ -879,9 +817,6 @@ "crates__linkme-impl-0.3.37": { "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "patch_args": [], - "patch_tool": "", - "patches": [], "remote_patch_strip": 1, "sha256": "77060ebe535362c3da75682cd17b0431017b6e7c5661e714fc69a7ad017d1301", "type": "tar.gz", @@ -889,15 +824,12 @@ "https://static.crates.io/crates/linkme-impl/0.3.37/download" ], "strip_prefix": "linkme-impl-0.3.37", - "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'protobuf'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"linkme_impl\",\n deps = [\n \"@crates__linkme-impl-0.3.37//:build_script_build\",\n \"@crates__proc-macro2-1.0.107//:proc_macro2\",\n \"@crates__quote-1.0.47//:quote\",\n \"@crates__syn-3.0.3//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=linkme-impl\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:wasm32-wasip1\": [],\n \"@rules_rust//rust/platform:x86_64-pc-windows-msvc\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-nixos-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.37\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n edition = \"2021\",\n pkg_name = \"linkme-impl\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=linkme-impl\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.3.37\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'protobuf'\n###############################################################################\n\nload(\n \"@rules_rust//cargo:defs.bzl\",\n \"cargo_build_script\",\n \"cargo_toml_env_vars\",\n)\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_proc_macro\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_proc_macro(\n name = \"linkme_impl\",\n deps = [\n \"@crates__linkme-impl-0.3.37//:build_script_build\",\n \"@crates__proc-macro2-1.0.107//:proc_macro2\",\n \"@crates__quote-1.0.47//:quote\",\n \"@crates__syn-3.0.5//:syn\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=linkme-impl\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:wasm32-wasip1\": [],\n \"@rules_rust//rust/platform:x86_64-pc-windows-msvc\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-nixos-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"0.3.37\",\n)\n\ncargo_build_script(\n name = \"_bs\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \"**/*.rs\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_name = \"build_script_build\",\n crate_root = \"build.rs\",\n data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n edition = \"2021\",\n pkg_name = \"linkme-impl\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=linkme-impl\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n version = \"0.3.37\",\n visibility = [\"//visibility:private\"],\n)\n\nalias(\n name = \"build_script_build\",\n actual = \":_bs\",\n tags = [\"manual\"],\n)\n" } }, "crates__memchr-2.8.3": { "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "patch_args": [], - "patch_tool": "", - "patches": [], "remote_patch_strip": 1, "sha256": "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98", "type": "tar.gz", @@ -911,9 +843,6 @@ "crates__num-traits-0.2.19": { "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "patch_args": [], - "patch_tool": "", - "patches": [], "remote_patch_strip": 1, "sha256": "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841", "type": "tar.gz", @@ -927,9 +856,6 @@ "crates__paste-1.0.15": { "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "patch_args": [], - "patch_tool": "", - "patches": [], "remote_patch_strip": 1, "sha256": "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a", "type": "tar.gz", @@ -943,9 +869,6 @@ "crates__proc-macro2-1.0.107": { "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "patch_args": [], - "patch_tool": "", - "patches": [], "remote_patch_strip": 1, "sha256": "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9", "type": "tar.gz", @@ -959,9 +882,6 @@ "crates__quote-1.0.47": { "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "patch_args": [], - "patch_tool": "", - "patches": [], "remote_patch_strip": 1, "sha256": "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001", "type": "tar.gz", @@ -975,9 +895,6 @@ "crates__regex-1.13.1": { "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "patch_args": [], - "patch_tool": "", - "patches": [], "remote_patch_strip": 1, "sha256": "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d", "type": "tar.gz", @@ -991,9 +908,6 @@ "crates__regex-automata-0.4.18": { "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "patch_args": [], - "patch_tool": "", - "patches": [], "remote_patch_strip": 1, "sha256": "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2", "type": "tar.gz", @@ -1007,9 +921,6 @@ "crates__regex-syntax-0.8.11": { "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "patch_args": [], - "patch_tool": "", - "patches": [], "remote_patch_strip": 1, "sha256": "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4", "type": "tar.gz", @@ -1023,9 +934,6 @@ "crates__rustversion-1.0.23": { "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "patch_args": [], - "patch_tool": "", - "patches": [], "remote_patch_strip": 1, "sha256": "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f", "type": "tar.gz", @@ -1039,9 +947,6 @@ "crates__syn-2.0.119": { "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "patch_args": [], - "patch_tool": "", - "patches": [], "remote_patch_strip": 1, "sha256": "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297", "type": "tar.gz", @@ -1052,28 +957,22 @@ "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'protobuf'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"syn\",\n deps = [\n \"@crates__proc-macro2-1.0.107//:proc_macro2\",\n \"@crates__quote-1.0.47//:quote\",\n \"@crates__unicode-ident-1.0.24//:unicode_ident\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"clone-impls\",\n \"default\",\n \"derive\",\n \"extra-traits\",\n \"full\",\n \"parsing\",\n \"printing\",\n \"proc-macro\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=syn\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:wasm32-wasip1\": [],\n \"@rules_rust//rust/platform:x86_64-pc-windows-msvc\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-nixos-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"2.0.119\",\n)\n" } }, - "crates__syn-3.0.3": { + "crates__syn-3.0.5": { "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "patch_args": [], - "patch_tool": "", - "patches": [], "remote_patch_strip": 1, - "sha256": "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3", + "sha256": "12df2e0110f65b775f769bb17ef989067a1d931b2eb822bd4346631eeada89f9", "type": "tar.gz", "urls": [ - "https://static.crates.io/crates/syn/3.0.3/download" + "https://static.crates.io/crates/syn/3.0.5/download" ], - "strip_prefix": "syn-3.0.3", - "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'protobuf'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"syn\",\n deps = [\n \"@crates__proc-macro2-1.0.107//:proc_macro2\",\n \"@crates__quote-1.0.47//:quote\",\n \"@crates__unicode-ident-1.0.24//:unicode_ident\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"clone-impls\",\n \"default\",\n \"derive\",\n \"parsing\",\n \"printing\",\n \"proc-macro\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=syn\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:wasm32-wasip1\": [],\n \"@rules_rust//rust/platform:x86_64-pc-windows-msvc\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-nixos-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"3.0.3\",\n)\n" + "strip_prefix": "syn-3.0.5", + "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'protobuf'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"syn\",\n deps = [\n \"@crates__proc-macro2-1.0.107//:proc_macro2\",\n \"@crates__quote-1.0.47//:quote\",\n \"@crates__unicode-ident-1.0.24//:unicode_ident\",\n ],\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_features = [\n \"clone-impls\",\n \"default\",\n \"derive\",\n \"parsing\",\n \"printing\",\n \"proc-macro\",\n ],\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=syn\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:wasm32-wasip1\": [],\n \"@rules_rust//rust/platform:x86_64-pc-windows-msvc\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-nixos-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"3.0.5\",\n)\n" } }, "crates__unicode-ident-1.0.24": { "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { - "patch_args": [], - "patch_tool": "", - "patches": [], "remote_patch_strip": 1, "sha256": "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75", "type": "tar.gz", @@ -1084,73 +983,30 @@ "build_file_content": "###############################################################################\n# @generated\n# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To \n# regenerate this file, run the following:\n#\n# bazel mod show_repo 'protobuf'\n###############################################################################\n\nload(\"@rules_rust//cargo:defs.bzl\", \"cargo_toml_env_vars\")\n\nload(\"@rules_rust//rust:defs.bzl\", \"rust_library\")\n\n# buildifier: disable=bzl-visibility\nload(\"@rules_rust//crate_universe/private:selects.bzl\", \"selects\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\ncargo_toml_env_vars(\n name = \"cargo_toml_env_vars\",\n src = \"Cargo.toml\",\n)\n\nrust_library(\n name = \"unicode_ident\",\n compile_data = glob(\n allow_empty = True,\n include = [\"**\"],\n exclude = [\n \"**/* *\",\n \".tmp_git_root/**/*\",\n \"BUILD\",\n \"BUILD.bazel\",\n \"WORKSPACE\",\n \"WORKSPACE.bazel\",\n ],\n ),\n crate_root = \"src/lib.rs\",\n edition = \"2021\",\n rustc_env_files = [\n \":cargo_toml_env_vars\",\n ],\n rustc_flags = [\n \"--cap-lints=allow\",\n ],\n srcs = glob(\n allow_empty = True,\n include = [\"**/*.rs\"],\n ),\n tags = [\n \"cargo-bazel\",\n \"crate-name=unicode-ident\",\n \"manual\",\n \"noclippy\",\n \"norustfmt\",\n ],\n target_compatible_with = select({\n \"@rules_rust//rust/platform:aarch64-apple-darwin\": [],\n \"@rules_rust//rust/platform:aarch64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:wasm32-unknown-unknown\": [],\n \"@rules_rust//rust/platform:wasm32-wasip1\": [],\n \"@rules_rust//rust/platform:x86_64-pc-windows-msvc\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-linux-gnu\": [],\n \"@rules_rust//rust/platform:x86_64-unknown-nixos-gnu\": [],\n \"//conditions:default\": [\"@platforms//:incompatible\"],\n }),\n version = \"1.0.24\",\n)\n" } } - }, - "recordedRepoMappingEntries": [ - [ - "bazel_features+", - "bazel_features_globals", - "bazel_features++version_extension+bazel_features_globals" - ], - [ - "bazel_features+", - "bazel_features_version", - "bazel_features++version_extension+bazel_features_version" - ], - [ - "rules_cc+", - "bazel_tools", - "bazel_tools" - ], - [ - "rules_cc+", - "cc_compatibility_proxy", - "rules_cc++compatibility_proxy+cc_compatibility_proxy" - ], - [ - "rules_cc+", - "rules_cc", - "rules_cc+" - ], - [ - "rules_cc++compatibility_proxy+cc_compatibility_proxy", - "rules_cc", - "rules_cc+" - ], - [ - "rules_rust+", - "bazel_features", - "bazel_features+" - ], - [ - "rules_rust+", - "bazel_skylib", - "bazel_skylib+" - ], - [ - "rules_rust+", - "bazel_tools", - "bazel_tools" - ], - [ - "rules_rust+", - "rules_cc", - "rules_cc+" - ], - [ - "rules_rust+", - "rules_rust", - "rules_rust+" - ] - ] + } } }, "@@rules_rust+//crate_universe/private:internal_extensions.bzl%cu_nr": { "general": { - "bzlTransitiveDigest": "xSSbyp9DXbDyAhOo726pmBAvcUUhi7amU7Lr5YiYEIg=", + "bzlTransitiveDigest": "nnvh33qLSR0WargH12WGfTJiOvvoJlJtGPRgV132tj0=", "usagesDigest": "tG3p3Nb5XxC7vWY/bcKdb//g0HoAxpxxH3F5/jBVlk4=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, + "recordedInputs": [ + "REPO_MAPPING:bazel_features+,bazel_features_globals bazel_features++version_extension+bazel_features_globals", + "REPO_MAPPING:bazel_features+,bazel_features_version bazel_features++version_extension+bazel_features_version", + "REPO_MAPPING:rules_cc+,bazel_skylib bazel_skylib+", + "REPO_MAPPING:rules_cc+,bazel_tools bazel_tools", + "REPO_MAPPING:rules_cc+,cc_compatibility_proxy rules_cc++compatibility_proxy+cc_compatibility_proxy", + "REPO_MAPPING:rules_cc+,platforms platforms", + "REPO_MAPPING:rules_cc+,rules_cc rules_cc+", + "REPO_MAPPING:rules_cc++compatibility_proxy+cc_compatibility_proxy,rules_cc rules_cc+", + "REPO_MAPPING:rules_rust+,bazel_features bazel_features+", + "REPO_MAPPING:rules_rust+,bazel_skylib bazel_skylib+", + "REPO_MAPPING:rules_rust+,bazel_tools bazel_tools", + "REPO_MAPPING:rules_rust+,cui rules_rust++cu+cui", + "REPO_MAPPING:rules_rust+,rrc rules_rust++i2+rrc", + "REPO_MAPPING:rules_rust+,rules_cc rules_cc+", + "REPO_MAPPING:rules_rust+,rules_rust rules_rust+" + ], "generatedRepoSpecs": { "cargo_bazel_bootstrap": { "repoRuleId": "@@rules_rust+//cargo/private:cargo_bootstrap.bzl%cargo_bootstrap_repository", @@ -1226,83 +1082,14 @@ "explicitRootModuleDirectDevDeps": [], "useAllRepos": "NO", "reproducible": false - }, - "recordedRepoMappingEntries": [ - [ - "bazel_features+", - "bazel_features_globals", - "bazel_features++version_extension+bazel_features_globals" - ], - [ - "bazel_features+", - "bazel_features_version", - "bazel_features++version_extension+bazel_features_version" - ], - [ - "rules_cc+", - "bazel_tools", - "bazel_tools" - ], - [ - "rules_cc+", - "cc_compatibility_proxy", - "rules_cc++compatibility_proxy+cc_compatibility_proxy" - ], - [ - "rules_cc+", - "rules_cc", - "rules_cc+" - ], - [ - "rules_cc++compatibility_proxy+cc_compatibility_proxy", - "rules_cc", - "rules_cc+" - ], - [ - "rules_rust+", - "bazel_features", - "bazel_features+" - ], - [ - "rules_rust+", - "bazel_skylib", - "bazel_skylib+" - ], - [ - "rules_rust+", - "bazel_tools", - "bazel_tools" - ], - [ - "rules_rust+", - "cui", - "rules_rust++cu+cui" - ], - [ - "rules_rust+", - "rrc", - "rules_rust++i2+rrc" - ], - [ - "rules_rust+", - "rules_cc", - "rules_cc+" - ], - [ - "rules_rust+", - "rules_rust", - "rules_rust+" - ] - ] + } } }, "@@toolchains_llvm+//toolchain/extensions:distributions.bzl%llvm_distributions": { "general": { - "bzlTransitiveDigest": "gCdXpBt3HBBc280OILOFheHmO7lXWXJYnPgYiTtyapI=", - "usagesDigest": "Gxd/8VJQJ2gEen1n0zokZ5b2dU+EtCFsb0NpgAJkCaw=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, + "bzlTransitiveDigest": "UjfWy+RWdwj4BIiZFchPZA3MIBFUkIKzj19B8/LDGko=", + "usagesDigest": "RMQmnjhQu0/s1mluVFIa5TjoFcqct9XtWtNP5Bjy1Ho=", + "recordedInputs": [], "generatedRepoSpecs": { "llvm_distributions_data": { "repoRuleId": "@@toolchains_llvm+//toolchain/internal:distributions_repo.bzl%llvm_distributions_repo", @@ -1315,8 +1102,7 @@ ] } } - }, - "recordedRepoMappingEntries": [] + } } } }, @@ -1646,6 +1432,667 @@ "27bab004c72b3d7bd05a69b6ec0fc54a309b4b78cc569dd963d8b3ec28bfdb8c" ] } + }, + "@@rules_python+//python/extensions:pip.bzl%pip": { + "dist_hashes": { + "https://pypi.org/simple": { + "anyio": { + "https://files.pythonhosted.org/packages/7b/a2/10639a79341f6c019dedc95bd48a4928eed9f1d1197f4c04f546fc7ae0ff/anyio-4.4.0-py3-none-any.whl": "c1b2d8f46a8a812513012e1107cb0e68c17159a7a594208005a57dc776e1bdc7", + "https://files.pythonhosted.org/packages/e6/e3/c4c8d473d6780ef1853d630d581f70d655b4f8d7553c6997958c283039a2/anyio-4.4.0.tar.gz": "5aadc6a1bbb7cdb0bede386cac5e2940f5e2ff3aa20277e991cf028e0585ce94" + }, + "backports-tarfile": { + "https://files.pythonhosted.org/packages/86/72/cd9b395f25e290e633655a100af28cb253e4393396264a98bd5f5951d50f/backports_tarfile-1.2.0.tar.gz": "d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991", + "https://files.pythonhosted.org/packages/b9/fa/123043af240e49752f1c4bd24da5053b6bd00cad78c2be53c0d1e8b975bc/backports.tarfile-1.2.0-py3-none-any.whl": "77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34" + }, + "blinker": { + "https://files.pythonhosted.org/packages/1e/57/a6a1721eff09598fb01f3c7cda070c1b6a0f12d63c83236edf79a440abcc/blinker-1.8.2.tar.gz": "8f77b09d3bf7c795e969e9486f39c2c5e9c39d4ee07424be2bc594ece9642d83", + "https://files.pythonhosted.org/packages/bb/2a/10164ed1f31196a2f7f3799368a821765c62851ead0e630ab52b8e14b4d0/blinker-1.8.2-py3-none-any.whl": "1779309f71bf239144b9399d06ae925637cf6634cf6bd131104184531bf67c01" + }, + "certifi": { + "https://files.pythonhosted.org/packages/4c/5b/b6ce21586237c77ce67d01dc5507039d444b630dd76611bbca2d8e5dcd91/certifi-2025.10.5.tar.gz": "47c09d31ccf2acf0be3f701ea53595ee7e0b8fa08801c6624be771df09ae7b43", + "https://files.pythonhosted.org/packages/e4/37/af0d2ef3967ac0d6113837b44a4f0bfe1328c2b9763bd5b1744520e5cfed/certifi-2025.10.5-py3-none-any.whl": "0f212c2744a9bb6de0c56639a6f68afe01ecd92d91f14ae897c4fe7bbeeef0de" + }, + "cffi": { + "https://files.pythonhosted.org/packages/05/eb/b86f2a2645b62adcfff53b0dd97e8dfafb5c8aa864bd0d9a2c2049a0d551/cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl": "5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0", + "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl": "3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", + "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl": "5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", + "https://files.pythonhosted.org/packages/12/4a/3dfd5f7850cbf0d06dc84ba9aa00db766b52ca38d8b86e3a38314d52498c/cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl": "b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", + "https://files.pythonhosted.org/packages/15/12/a7a79bd0df4c3bff744b2d7e52cc1b68d5e7e427b384252c42366dc1ecbc/cffi-2.0.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl": "3f4d46d8b35698056ec29bca21546e1551a205058ae1a181d871e278b0b28165", + "https://files.pythonhosted.org/packages/1f/74/cc4096ce66f5939042ae094e2e96f53426a979864aa1f96a621ad128be27/cffi-2.0.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl": "61d028e90346df14fedc3d1e5441df818d095f3b87d286825dfcbd6459b7ef63", + "https://files.pythonhosted.org/packages/21/7a/13b24e70d2f90a322f2900c5d8e1f14fa7e2a6b3332b7309ba7b2ba51a5a/cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl": "cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495", + "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl": "7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", + "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl": "737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", + "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl": "c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", + "https://files.pythonhosted.org/packages/2b/e7/7c769804eb75e4c4b35e658dba01de1640a351a9653c3d49ca89d16ccc91/cffi-2.0.0-cp39-cp39-musllinux_1_2_x86_64.whl": "89472c9762729b5ae1ad974b777416bfda4ac5642423fa93bd57a09204712322", + "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl": "7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", + "https://files.pythonhosted.org/packages/32/f2/81b63e288295928739d715d00952c8c6034cb6c6a516b17d37e0c8be5600/cffi-2.0.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.whl": "cb527a79772e5ef98fb1d700678fe031e353e765d1ca2d409c92263c6d43e09f", + "https://files.pythonhosted.org/packages/33/fa/072dd15ae27fbb4e06b437eb6e944e75b068deb09e2a2826039e49ee2045/cffi-2.0.0-cp310-cp310-win_amd64.whl": "b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739", + "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl": "6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", + "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl": "19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", + "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl": "81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", + "https://files.pythonhosted.org/packages/3d/de/38d9726324e127f727b4ecc376bc85e505bfe61ef130eaf3f290c6847dd4/cffi-2.0.0-cp39-cp39-macosx_11_0_arm64.whl": "de8dad4425a6ca6e4e5e297b27b5c824ecc7581910bf9aee86cb6835e6812aa7", + "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl": "9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", + "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl": "087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", + "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl": "a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", + "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl": "afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", + "https://files.pythonhosted.org/packages/49/72/ff2d12dbf21aca1b32a40ed792ee6b40f6dc3a9cf1644bd7ef6e95e0ac5e/cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl": "8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb", + "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl": "45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", + "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl": "00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", + "https://files.pythonhosted.org/packages/4f/27/6933a8b2562d7bd1fb595074cf99cc81fc3789f6a6c05cdabb46284a3188/cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl": "3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb", + "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl": "2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", + "https://files.pythonhosted.org/packages/50/bd/b1a6362b80628111e6653c961f987faa55262b4002fcec42308cad1db680/cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl": "53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c", + "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl": "d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", + "https://files.pythonhosted.org/packages/54/8f/a1e836f82d8e32a97e6b29cc8f641779181ac7363734f12df27db803ebda/cffi-2.0.0-cp39-cp39-win_amd64.whl": "b882b3df248017dba09d6b16defe9b5c407fe32fc7c65a9c69798e6175601be9", + "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl": "c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", + "https://files.pythonhosted.org/packages/60/99/c9dc110974c59cc981b1f5b66e1d8af8af764e00f0293266824d9c4254bc/cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl": "e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5", + "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl": "3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", + "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl": "da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", + "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl": "9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", + "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl": "fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", + "https://files.pythonhosted.org/packages/93/d7/516d984057745a6cd96575eea814fe1edd6646ee6efd552fb7b0921dec83/cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl": "0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44", + "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl": "4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", + "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl": "c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", + "https://files.pythonhosted.org/packages/98/29/9b366e70e243eb3d14a5cb488dfd3a0b6b2f1fb001a203f653b93ccfac88/cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl": "fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453", + "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl": "c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", + "https://files.pythonhosted.org/packages/9b/13/c92e36358fbcc39cf0962e83223c9522154ee8630e1df7c0b3a39a8124e2/cffi-2.0.0-cp39-cp39-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl": "4647afc2f90d1ddd33441e5b0e85b16b12ddec4fca55f0d9671fef036ecca27c", + "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl": "f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49", + "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl": "dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", + "https://files.pythonhosted.org/packages/9f/e0/6cbe77a53acf5acc7c08cc186c9928864bd7c005f9efd0d126884858a5fe/cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl": "9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4", + "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl": "1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", + "https://files.pythonhosted.org/packages/a3/ad/5c51c1c7600bdd7ed9a24a203ec255dccdd0ebf4527f7b922a0bde2fb6ed/cffi-2.0.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl": "e6e73b9e02893c764e7e8d5bb5ce277f1a009cd5243f8228f75f842bf937c534", + "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl": "d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", + "https://files.pythonhosted.org/packages/aa/d9/6218d78f920dcd7507fc16a766b5ef8f3b913cc7aa938e7fc80b9978d089/cffi-2.0.0-cp39-cp39-win32.whl": "2081580ebb843f759b9f617314a24ed5738c51d2aee65d31e02f6f7a2b97707a", + "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl": "94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", + "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl": "0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", + "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl": "66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", + "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl": "07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", + "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl": "baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", + "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl": "12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", + "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl": "2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", + "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl": "730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", + "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl": "203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", + "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl": "d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", + "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl": "7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", + "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl": "d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", + "https://files.pythonhosted.org/packages/c0/cc/08ed5a43f2996a16b462f64a7055c6e962803534924b9b2f1371d8c00b7b/cffi-2.0.0-cp39-cp39-macosx_10_13_x86_64.whl": "fe562eb1a64e67dd297ccc4f5addea2501664954f2692b69a76449ec7913ecbf", + "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl": "1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", + "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl": "38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", + "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl": "256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", + "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl": "dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", + "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl": "28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", + "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl": "b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", + "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl": "24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", + "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl": "8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", + "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl": "b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", + "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl": "6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", + "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl": "8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", + "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl": "92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", + "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl": "6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", + "https://files.pythonhosted.org/packages/e2/cc/027d7fb82e58c48ea717149b03bcadcbdc293553edb283af792bd4bcbb3f/cffi-2.0.0-cp310-cp310-win32.whl": "1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a", + "https://files.pythonhosted.org/packages/e8/be/f6424d1dc46b1091ffcc8964fa7c0ab0cd36839dd2761b49c90481a6ba1b/cffi-2.0.0-cp39-cp39-musllinux_1_2_aarch64.whl": "0f6084a0ea23d05d20c3edcda20c3d006f9b6f3fefeac38f59262e10cef47ee2", + "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl": "6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", + "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz": "44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", + "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl": "74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", + "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl": "f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", + "https://files.pythonhosted.org/packages/f7/e0/dda537c2309817edf60109e39265f24f24aa7f050767e22c98c53fe7f48b/cffi-2.0.0-cp39-cp39-musllinux_1_2_i686.whl": "1cd13c99ce269b3ed80b417dcd591415d3372bcac067009b6e0f59c7d4015e65", + "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl": "da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", + "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl": "21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe" + }, + "charset-normalizer": { + "https://files.pythonhosted.org/packages/00/bd/ef9c88464b126fa176f4ef4a317ad9b6f4d30b2cffbc43386062367c3e2c/charset_normalizer-3.4.3-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl": "8999f965f922ae054125286faf9f11bc6932184b93011d138925a1773830bbe9", + "https://files.pythonhosted.org/packages/02/f7/3611b32318b30974131db62b4043f335861d4d9b49adc6d57c1149cc49d4/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_aarch64.whl": "ccf600859c183d70eb47e05a44cd80a4ce77394d1ac0f79dbd2dd90a69a3a049", + "https://files.pythonhosted.org/packages/04/9a/914d294daa4809c57667b77470533e65def9c0be1ef8b4c1183a99170e9d/charset_normalizer-3.4.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl": "fb731e5deb0c7ef82d698b0f4c5bb724633ee2a489401594c5c88b02e6cb15f7", + "https://files.pythonhosted.org/packages/05/35/bb59b1cd012d7196fc81c2f5879113971efc226a63812c9cf7f89fe97c40/charset_normalizer-3.4.3-cp38-cp38-win_amd64.whl": "5d8d01eac18c423815ed4f4a2ec3b439d654e55ee4ad610e153cf02faf67ea40", + "https://files.pythonhosted.org/packages/05/6b/e2539a0a4be302b481e8cafb5af8792da8093b486885a1ae4d15d452bcec/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_ppc64le.whl": "42e5088973e56e31e4fa58eb6bd709e42fc03799c11c42929592889a2e54c491", + "https://files.pythonhosted.org/packages/06/57/84722eefdd338c04cf3030ada66889298eaedf3e7a30a624201e0cbe424a/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_s390x.whl": "30a96e1e1f865f78b030d65241c1ee850cdf422d869e9028e2fc1d5e4db73b92", + "https://files.pythonhosted.org/packages/0c/52/8b0c6c3e53f7e546a5e49b9edb876f379725914e1130297f3b423c7b71c5/charset_normalizer-3.4.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl": "c60e092517a73c632ec38e290eba714e9627abe9d301c8c8a12ec32c314a2a4b", + "https://files.pythonhosted.org/packages/16/ab/0233c3231af734f5dfcf0844aa9582d5a1466c985bbed6cedab85af9bfe3/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl": "1606f4a55c0fd363d754049cdf400175ee96c992b1f8018b993941f221221c5f", + "https://files.pythonhosted.org/packages/17/e5/5e67ab85e6d22b04641acb5399c8684f4d37caf7558a53859f0283a650e9/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl": "2001a39612b241dae17b4687898843f254f8748b796a2e16f1051a17078d991d", + "https://files.pythonhosted.org/packages/1a/79/ae516e678d6e32df2e7e740a7be51dc80b700e2697cb70054a0f1ac2c955/charset_normalizer-3.4.3-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl": "3653fad4fe3ed447a596ae8638b437f827234f01a8cd801842e43f3d0a6b281b", + "https://files.pythonhosted.org/packages/20/30/5f64fe3981677fe63fa987b80e6c01042eb5ff653ff7cec1b7bd9268e54e/charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_ppc64le.whl": "2c322db9c8c89009a990ef07c3bcc9f011a3269bc06782f916cd3d9eed7c9312", + "https://files.pythonhosted.org/packages/21/40/5188be1e3118c82dcb7c2a5ba101b783822cfb413a0268ed3be0468532de/charset_normalizer-3.4.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl": "cc9370a2da1ac13f0153780040f465839e6cccb4a1e44810124b4e22483c93fe", + "https://files.pythonhosted.org/packages/22/82/63a45bfc36f73efe46731a3a71cb84e2112f7e0b049507025ce477f0f052/charset_normalizer-3.4.3-cp38-cp38-macosx_10_9_universal2.whl": "0f2be7e0cf7754b9a30eb01f4295cc3d4358a479843b31f328afd210e2c7598c", + "https://files.pythonhosted.org/packages/2a/91/26c3036e62dfe8de8061182d33be5025e2424002125c9500faff74a6735e/charset_normalizer-3.4.3-cp310-cp310-win32.whl": "d79c198e27580c8e958906f803e63cddb77653731be08851c7df0b1a14a8fc0f", + "https://files.pythonhosted.org/packages/2f/36/77da9c6a328c54d17b960c89eccacfab8271fdaaa228305330915b88afa9/charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_x86_64.whl": "1e8ac75d72fa3775e0b7cb7e4629cec13b7514d928d15ef8ea06bca03ef01cae", + "https://files.pythonhosted.org/packages/31/e7/883ee5676a2ef217a40ce0bffcc3d0dfbf9e64cbcfbdf822c52981c3304b/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_s390x.whl": "cc34f233c9e71701040d772aa7490318673aa7164a0efe3172b2981218c26d93", + "https://files.pythonhosted.org/packages/33/9e/eca49d35867ca2db336b6ca27617deed4653b97ebf45dfc21311ce473c37/charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_x86_64.whl": "78deba4d8f9590fe4dae384aeff04082510a709957e968753ff3c48399f6f92a", + "https://files.pythonhosted.org/packages/37/60/5d0d74bc1e1380f0b72c327948d9c2aca14b46a9efd87604e724260f384c/charset_normalizer-3.4.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl": "07a0eae9e2787b586e129fdcbe1af6997f8d0e5abaa0bc98c0e20e124d67e601", + "https://files.pythonhosted.org/packages/39/c6/99271dc37243a4f925b09090493fb96c9333d7992c6187f5cfe5312008d2/charset_normalizer-3.4.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl": "23b6b24d74478dc833444cbd927c338349d6ae852ba53a0d02a2de1fce45b96e", + "https://files.pythonhosted.org/packages/39/f5/3b3836ca6064d0992c58c7561c6b6eee1b3892e9665d650c803bd5614522/charset_normalizer-3.4.3-cp312-cp312-win_amd64.whl": "86df271bf921c2ee3818f0522e9a5b8092ca2ad8b065ece5d7d9d0e9f4849bcc", + "https://files.pythonhosted.org/packages/3a/a4/b3b6c76e7a635748c4421d2b92c7b8f90a432f98bda5082049af37ffc8e3/charset_normalizer-3.4.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl": "00237675befef519d9af72169d8604a067d92755e84fe76492fef5441db05b91", + "https://files.pythonhosted.org/packages/3b/38/20a1f44e4851aa1c9105d6e7110c9d020e093dfa5836d712a5f074a12bf7/charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_ppc64le.whl": "4ca4c094de7771a98d7fbd67d9e5dbf1eb73efa4f744a730437d8a3a5cf994f0", + "https://files.pythonhosted.org/packages/45/8c/dcef87cfc2b3f002a6478f38906f9040302c68aebe21468090e39cde1445/charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_x86_64.whl": "88ab34806dea0671532d3f82d82b85e8fc23d7b2dd12fa837978dad9bb392a34", + "https://files.pythonhosted.org/packages/4c/92/27dbe365d34c68cfe0ca76f1edd70e8705d82b378cb54ebbaeabc2e3029d/charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_ppc64le.whl": "939578d9d8fd4299220161fdd76e86c6a251987476f5243e8864a7844476ba14", + "https://files.pythonhosted.org/packages/50/10/c117806094d2c956ba88958dab680574019abc0c02bcf57b32287afca544/charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_x86_64.whl": "a2d08ac246bb48479170408d6c19f6385fa743e7157d716e144cad849b2dd94b", + "https://files.pythonhosted.org/packages/50/ee/f4704bad8201de513fdc8aac1cabc87e38c5818c93857140e06e772b5892/charset_normalizer-3.4.3-cp312-cp312-win32.whl": "fb6fecfd65564f208cbf0fba07f107fb661bcd1a7c389edbced3f7a493f70e37", + "https://files.pythonhosted.org/packages/59/c0/a74f3bd167d311365e7973990243f32c35e7a94e45103125275b9e6c479f/charset_normalizer-3.4.3-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl": "252098c8c7a873e17dd696ed98bbe91dbacd571da4b87df3736768efa7a792e4", + "https://files.pythonhosted.org/packages/60/f5/4659a4cb3c4ec146bec80c32d8bb16033752574c20b1252ee842a95d1a1e/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl": "1bb60174149316da1c35fa5233681f7c0f9f514509b8e399ab70fea5f17e45c9", + "https://files.pythonhosted.org/packages/61/c5/dc3ba772489c453621ffc27e8978a98fe7e41a93e787e5e5bde797f1dddb/charset_normalizer-3.4.3-cp38-cp38-win32.whl": "ec557499516fc90fd374bf2e32349a2887a876fbf162c160e3c01b6849eaf557", + "https://files.pythonhosted.org/packages/61/f1/190d9977e0084d3f1dc169acd060d479bbbc71b90bf3e7bf7b9927dec3eb/charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_aarch64.whl": "96b2b3d1a83ad55310de8c7b4a2d04d9277d5591f40761274856635acc5fcb30", + "https://files.pythonhosted.org/packages/63/86/9cbd533bd37883d467fcd1bd491b3547a3532d0fbb46de2b99feeebf185e/charset_normalizer-3.4.3-cp39-cp39-win32.whl": "16a8770207946ac75703458e2c743631c79c59c5890c80011d536248f8eaa432", + "https://files.pythonhosted.org/packages/64/d1/f9d141c893ef5d4243bc75c130e95af8fd4bc355beff06e9b1e941daad6e/charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_ppc64le.whl": "5b413b0b1bfd94dbf4023ad6945889f374cd24e3f62de58d6bb102c4d9ae534a", + "https://files.pythonhosted.org/packages/64/d4/9eb4ff2c167edbbf08cdd28e19078bf195762e9bd63371689cab5ecd3d0d/charset_normalizer-3.4.3-cp311-cp311-win32.whl": "6cf8fd4c04756b6b60146d98cd8a77d0cdae0e1ca20329da2ac85eed779b6849", + "https://files.pythonhosted.org/packages/65/1a/7425c952944a6521a9cfa7e675343f83fd82085b8af2b1373a2409c683dc/charset_normalizer-3.4.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl": "d0e909868420b7049dafd3a31d45125b31143eec59235311fc4c57ea26a4acd2", + "https://files.pythonhosted.org/packages/65/ca/2135ac97709b400c7654b4b764daf5c5567c2da45a30cdd20f9eefe2d658/charset_normalizer-3.4.3-cp313-cp313-macosx_10_13_universal2.whl": "14c2a87c65b351109f6abfc424cab3927b3bdece6f706e4d12faaf3d52ee5efe", + "https://files.pythonhosted.org/packages/70/99/f1c3bdcfaa9c45b3ce96f70b14f070411366fa19549c1d4832c935d8e2c3/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_x86_64.whl": "18343b2d246dc6761a249ba1fb13f9ee9a2bcd95decc767319506056ea4ad4dc", + "https://files.pythonhosted.org/packages/71/11/98a04c3c97dd34e49c7d247083af03645ca3730809a5509443f3c37f7c99/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl": "41d1fc408ff5fdfb910200ec0e74abc40387bccb3252f3f27c0676731df2b2c8", + "https://files.pythonhosted.org/packages/72/2a/aff5dd112b2f14bcc3462c312dce5445806bfc8ab3a7328555da95330e4b/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_x86_64.whl": "d716a916938e03231e86e43782ca7878fb602a125a91e7acb8b5112e2e96ac16", + "https://files.pythonhosted.org/packages/77/d9/cbcf1a2a5c7d7856f11e7ac2d782aec12bdfea60d104e60e0aa1c97849dc/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_ppc64le.whl": "fdabf8315679312cfa71302f9bd509ded4f2f263fb5b765cf1433b39106c3cc9", + "https://files.pythonhosted.org/packages/7a/03/cbb6fac9d3e57f7e07ce062712ee80d80a5ab46614684078461917426279/charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_aarch64.whl": "d95bfb53c211b57198bb91c46dd5a2d8018b3af446583aab40074bf7988401cb", + "https://files.pythonhosted.org/packages/7d/a8/c6ec5d389672521f644505a257f50544c074cf5fc292d5390331cd6fc9c3/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl": "0cacf8f7297b0c4fcb74227692ca46b4a5852f8f4f24b3c766dd94a1075c4884", + "https://files.pythonhosted.org/packages/7e/61/19b36f4bd67f2793ab6a99b979b4e4f3d8fc754cbdffb805335df4337126/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_ppc64le.whl": "53cd68b185d98dde4ad8990e56a58dea83a4162161b1ea9272e5c9182ce415e0", + "https://files.pythonhosted.org/packages/7e/95/42aa2156235cbc8fa61208aded06ef46111c4d3f0de233107b3f38631803/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl": "416175faf02e4b0810f1f38bcb54682878a4af94059a1cd63b8747244420801f", + "https://files.pythonhosted.org/packages/7f/b5/991245018615474a60965a7c9cd2b4efbaabd16d582a5547c47ee1c7730b/charset_normalizer-3.4.3-cp311-cp311-macosx_10_9_universal2.whl": "b256ee2e749283ef3ddcff51a675ff43798d92d746d1a6e4631bf8c707d22d0b", + "https://files.pythonhosted.org/packages/82/10/0fd19f20c624b278dddaf83b8464dcddc2456cb4b02bb902a6da126b87a1/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl": "3cfb2aad70f2c6debfbcb717f23b7eb55febc0bb23dcffc0f076009da10c6392", + "https://files.pythonhosted.org/packages/83/2d/5fd176ceb9b2fc619e63405525573493ca23441330fcdaee6bef9460e924/charset_normalizer-3.4.3.tar.gz": "6fce4b8500244f6fcb71465d4a4930d132ba9ab8e71a7859e6a5d59851068d14", + "https://files.pythonhosted.org/packages/85/9a/d891f63722d9158688de58d050c59dc3da560ea7f04f4c53e769de5140f5/charset_normalizer-3.4.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl": "74d77e25adda8581ffc1c720f1c81ca082921329452eba58b16233ab1842141c", + "https://files.pythonhosted.org/packages/86/9e/f552f7a00611f168b9a5865a1414179b2c6de8235a4fa40189f6f79a1753/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl": "30d006f98569de3459c2fc1f2acde170b7b2bd265dc1943e87e1a4efe1b67c31", + "https://files.pythonhosted.org/packages/87/df/b7737ff046c974b183ea9aa111b74185ac8c3a326c6262d413bd5a1b8c69/charset_normalizer-3.4.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl": "0e78314bdc32fa80696f72fa16dc61168fda4d6a0c014e0380f9d02f0e5d8a07", + "https://files.pythonhosted.org/packages/8a/1f/f041989e93b001bc4e44bb1669ccdcf54d3f00e628229a85b08d330615c5/charset_normalizer-3.4.3-py3-none-any.whl": "ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a", + "https://files.pythonhosted.org/packages/8e/91/b5a06ad970ddc7a0e513112d40113e834638f4ca1120eb727a249fb2715e/charset_normalizer-3.4.3-cp314-cp314-macosx_10_13_universal2.whl": "3cd35b7e8aedeb9e34c41385fda4f73ba609e561faedfae0a9e75e44ac558a15", + "https://files.pythonhosted.org/packages/99/04/baae2a1ea1893a01635d475b9261c889a18fd48393634b6270827869fa34/charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_s390x.whl": "fd10de089bcdcd1be95a2f73dbe6254798ec1bda9f450d5828c96f93e2536b9c", + "https://files.pythonhosted.org/packages/9a/8f/ae790790c7b64f925e5c953b924aaa42a243fb778fed9e41f147b2a5715a/charset_normalizer-3.4.3-cp313-cp313-win_amd64.whl": "cf1ebb7d78e1ad8ec2a8c4732c7be2e736f6e5123a4146c5b89c9d1f585f8cef", + "https://files.pythonhosted.org/packages/a0/e4/5a075de8daa3ec0745a9a3b54467e0c2967daaaf2cec04c845f73493e9a1/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl": "18b97b8404387b96cdbd30ad660f6407799126d26a39ca65729162fd810a99aa", + "https://files.pythonhosted.org/packages/a3/ad/b0081f2f99a4b194bcbb1934ef3b12aa4d9702ced80a37026b7607c72e58/charset_normalizer-3.4.3-cp313-cp313-win32.whl": "6fb70de56f1859a3f71261cbe41005f56a7842cc348d3aeb26237560bfa5e0ce", + "https://files.pythonhosted.org/packages/a4/fa/384d2c0f57edad03d7bec3ebefb462090d8905b4ff5a2d2525f3bb711fac/charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_s390x.whl": "02425242e96bcf29a49711b0ca9f37e451da7c70562bc10e8ed992a5a7a25cc0", + "https://files.pythonhosted.org/packages/ae/02/e29e22b4e02839a0e4a06557b1999d0a47db3567e82989b5bb21f3fbbd9f/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_aarch64.whl": "027b776c26d38b7f15b26a5da1044f376455fb3766df8fc38563b4efbc515154", + "https://files.pythonhosted.org/packages/b0/a8/6f5bcf1bcf63cb45625f7c5cadca026121ff8a6c8a3256d8d8cd59302663/charset_normalizer-3.4.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl": "257f26fed7d7ff59921b78244f3cd93ed2af1800ff048c33f624c87475819dd7", + "https://files.pythonhosted.org/packages/b7/8c/9839225320046ed279c6e839d51f028342eb77c91c89b8ef2549f951f3ec/charset_normalizer-3.4.3-cp314-cp314-win32.whl": "c6dbd0ccdda3a2ba7c2ecd9d77b37f3b5831687d8dc1b6ca5f56a4880cc7b7ce", + "https://files.pythonhosted.org/packages/c1/35/6525b21aa0db614cf8b5792d232021dca3df7f90a1944db934efa5d20bb1/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_x86_64.whl": "320e8e66157cc4e247d9ddca8e21f427efc7a04bbd0ac8a9faf56583fa543f9f", + "https://files.pythonhosted.org/packages/c2/a9/3865b02c56f300a6f94fc631ef54f0a8a29da74fb45a773dfd3dcd380af7/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_aarch64.whl": "6aab0f181c486f973bc7262a97f5aca3ee7e1437011ef0c2ec04b5a11d16c927", + "https://files.pythonhosted.org/packages/c2/ca/9a0983dd5c8e9733565cf3db4df2b0a2e9a82659fd8aa2a868ac6e4a991f/charset_normalizer-3.4.3-cp39-cp39-macosx_10_9_universal2.whl": "70bfc5f2c318afece2f5838ea5e4c3febada0be750fcf4775641052bbba14d05", + "https://files.pythonhosted.org/packages/c4/72/d3d0e9592f4e504f9dea08b8db270821c909558c353dc3b457ed2509f2fb/charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_aarch64.whl": "1ef99f0456d3d46a50945c98de1774da86f8e992ab5c77865ea8b8195341fc19", + "https://files.pythonhosted.org/packages/c5/35/9c99739250742375167bc1b1319cd1cec2bf67438a70d84b2e1ec4c9daa3/charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_s390x.whl": "b5e3b2d152e74e100a9e9573837aba24aab611d39428ded46f4e4022ea7d1942", + "https://files.pythonhosted.org/packages/c7/2a/ae245c41c06299ec18262825c1569c5d3298fc920e4ddf56ab011b417efd/charset_normalizer-3.4.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl": "13faeacfe61784e2559e690fc53fa4c5ae97c6fcedb8eb6fb8d0a15b475d2c64", + "https://files.pythonhosted.org/packages/ce/d6/7e805c8e5c46ff9729c49950acc4ee0aeb55efb8b3a56687658ad10c3216/charset_normalizer-3.4.3-cp39-cp39-win_amd64.whl": "d22dbedd33326a4a5190dd4fe9e9e693ef12160c77382d9e87919bce54f3d4ca", + "https://files.pythonhosted.org/packages/ce/ec/1edc30a377f0a02689342f214455c3f6c2fbedd896a1d2f856c002fc3062/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl": "b89bc04de1d83006373429975f8ef9e7932534b8cc9ca582e4db7d20d91816db", + "https://files.pythonhosted.org/packages/d6/98/f3b8013223728a99b908c9344da3aa04ee6e3fa235f19409033eda92fb78/charset_normalizer-3.4.3-cp310-cp310-macosx_10_9_universal2.whl": "fb7f67a1bfa6e40b438170ebdc8158b78dc465a5a67b6dde178a46987b244a72", + "https://files.pythonhosted.org/packages/e1/ef/dd08b2cac9284fd59e70f7d97382c33a3d0a926e45b15fc21b3308324ffd/charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_s390x.whl": "511729f456829ef86ac41ca78c63a5cb55240ed23b4b737faca0eb1abb1c41bc", + "https://files.pythonhosted.org/packages/e2/c6/f05db471f81af1fa01839d44ae2a8bfeec8d2a8b4590f16c4e7393afd323/charset_normalizer-3.4.3-cp310-cp310-win_amd64.whl": "c6e490913a46fa054e03699c70019ab869e990270597018cef1d8562132c2669", + "https://files.pythonhosted.org/packages/e2/e6/63bb0e10f90a8243c5def74b5b105b3bbbfb3e7bb753915fe333fb0c11ea/charset_normalizer-3.4.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl": "585f3b2a80fbd26b048a0be90c5aae8f06605d3c92615911c3a2b03a8a3b796f", + "https://files.pythonhosted.org/packages/e4/69/132eab043356bba06eb333cc2cc60c6340857d0a2e4ca6dc2b51312886b3/charset_normalizer-3.4.3-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl": "34a7f768e3f985abdb42841e20e17b330ad3aaf4bb7e7aeeb73db2e70f077b99", + "https://files.pythonhosted.org/packages/e9/5e/14c94999e418d9b87682734589404a25854d5f5d0408df68bc15b6ff54bb/charset_normalizer-3.4.3-cp312-cp312-macosx_10_13_universal2.whl": "e28e334d3ff134e88989d90ba04b47d84382a828c061d0d1027b1b12a62b39b1", + "https://files.pythonhosted.org/packages/ee/7a/36fbcf646e41f710ce0a563c1c9a343c6edf9be80786edeb15b6f62e17db/charset_normalizer-3.4.3-cp314-cp314-win_amd64.whl": "73dc19b562516fc9bcf6e5d6e596df0b4eb98d87e4f79f3ae71840e6ed21361c", + "https://files.pythonhosted.org/packages/f0/c9/a2c9c2a355a8594ce2446085e2ec97fd44d323c684ff32042e2a6b718e1d/charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_aarch64.whl": "c6f162aabe9a91a309510d74eeb6507fab5fff92337a15acbe77753d88d9dcf0", + "https://files.pythonhosted.org/packages/f1/e5/38421987f6c697ee3722981289d554957c4be652f963d71c5e46a262e135/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl": "8dcfc373f888e4fb39a7bc57e93e3b845e7f462dacc008d9749568b1c4ece096", + "https://files.pythonhosted.org/packages/f4/9c/996a4a028222e7761a96634d1820de8a744ff4327a00ada9c8942033089b/charset_normalizer-3.4.3-cp311-cp311-win_amd64.whl": "31a9a6f775f9bcd865d88ee350f0ffb0e25936a7f930ca98995c05abf1faf21c", + "https://files.pythonhosted.org/packages/f6/42/6f45efee8697b89fda4d50580f292b8f7f9306cb2971d4b53f8914e4d890/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_s390x.whl": "bd28b817ea8c70215401f657edef3a8aa83c29d447fb0b622c35403780ba11d5", + "https://files.pythonhosted.org/packages/fc/eb/a2ffb08547f4e1e5415fb69eb7db25932c52a52bed371429648db4d84fb1/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl": "c6fd51128a41297f5409deab284fecbe5305ebd7e5a1f959bee1c054622b7018" + }, + "cryptography": { + "https://files.pythonhosted.org/packages/03/11/5e395f961d6868269835dee1bafec6a1ac176505a167f68b7d8818431068/cryptography-46.0.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl": "ebd6daf519b9f189f85c479427bbd6e9c9037862cf8fe89ee35503bd209ed902", + "https://files.pythonhosted.org/packages/0b/5d/4a8f770695d73be252331e60e526291e3df0c9b27556a90a6b47bccca4c2/cryptography-46.0.7-cp311-abi3-macosx_10_9_universal2.whl": "ea42cbe97209df307fdc3b155f1b6fa2577c0defa8f1f7d3be7d31d189108ad4", + "https://files.pythonhosted.org/packages/0f/54/6bbbfc5efe86f9d71041827b793c24811a017c6ac0fd12883e4caa86b8ed/cryptography-46.0.7-cp311-abi3-manylinux_2_28_ppc64le.whl": "cbd5fb06b62bd0721e1170273d3f4d5a277044c47ca27ee257025146c34cbdd1", + "https://files.pythonhosted.org/packages/10/f2/19ceb3b3dc14009373432af0c13f46aa08e3ce334ec6eff13492e1812ccd/cryptography-46.0.7-cp311-abi3-musllinux_1_2_x86_64.whl": "5d1c02a14ceb9148cc7816249f64f623fbfee39e8c03b3650d842ad3f34d637e", + "https://files.pythonhosted.org/packages/16/01/0cd51dd86ab5b9befe0d031e276510491976c3a80e9f6e31810cce46c4ad/cryptography-46.0.7-cp38-abi3-manylinux_2_31_armv7l.whl": "cdfbe22376065ffcf8be74dc9a909f032df19bc58a699456a21712d6e5eabfd0", + "https://files.pythonhosted.org/packages/1a/bb/a5c213c19ee94b15dfccc48f363738633a493812687f5567addbcbba9f6f/cryptography-46.0.7-cp311-abi3-win32.whl": "d23c8ca48e44ee015cd0a54aeccdf9f09004eba9fc96f38c911011d9ff1bd457", + "https://files.pythonhosted.org/packages/20/2a/1b016902351a523aa2bd446b50a5bc1175d7a7d1cf90fe2ef904f9b84ebc/cryptography-46.0.7-pp311-pypy311_pp73-win_amd64.whl": "258514877e15963bd43b558917bc9f54cf7cf866c38aa576ebf47a77ddbc43a4", + "https://files.pythonhosted.org/packages/28/17/b59a741645822ec6d04732b43c5d35e4ef58be7bfa84a81e5ae6f05a1d33/cryptography-46.0.7-cp314-cp314t-musllinux_1_2_aarch64.whl": "fcd8eac50d9138c1d7fc53a653ba60a2bee81a505f9f8850b6b2888555a45d0e", + "https://files.pythonhosted.org/packages/2b/02/7788f9fefa1d060ca68717c3901ae7fffa21ee087a90b7f23c7a603c32ae/cryptography-46.0.7-cp311-abi3-win_amd64.whl": "397655da831414d165029da9bc483bed2fe0e75dde6a1523ec2fe63f3c46046b", + "https://files.pythonhosted.org/packages/2d/cf/054b9d8220f81509939599c8bdbc0c408dbd2bdd41688616a20731371fe0/cryptography-46.0.7-cp311-abi3-manylinux_2_28_x86_64.whl": "420b1e4109cc95f0e5700eed79908cef9268265c773d3a66f7af1eef53d409ef", + "https://files.pythonhosted.org/packages/32/a8/9f0e4ed57ec9cebe506e58db11ae472972ecb0c659e4d52bbaee80ca340a/cryptography-46.0.7-cp314-cp314t-win_amd64.whl": "e06acf3c99be55aa3b516397fe42f5855597f430add9c17fa46bf2e0fb34c9bb", + "https://files.pythonhosted.org/packages/36/5f/313586c3be5a2fbe87e4c9a254207b860155a8e1f3cca99f9910008e7d08/cryptography-46.0.7-cp311-abi3-manylinux_2_34_aarch64.whl": "8a469028a86f12eb7d2fe97162d0634026d92a21f3ae0ac87ed1c4a447886c83", + "https://files.pythonhosted.org/packages/3a/ea/075aac6a84b7c271578d81a2f9968acb6e273002408729f2ddff517fed4a/cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl": "d3b99c535a9de0adced13d159c5a9cf65c325601aa30f4be08afd680643e9c15", + "https://files.pythonhosted.org/packages/3d/4c/7d258f169ae71230f25d9f3d06caabcff8c3baf0978e2b7d65e0acac3827/cryptography-46.0.7-cp314-cp314t-manylinux_2_31_armv7l.whl": "60627cf07e0d9274338521205899337c5d18249db56865f943cbe753aa96f40f", + "https://files.pythonhosted.org/packages/40/53/8ed1cf4c3b9c8e611e7122fb56f1c32d09e1fff0f1d77e78d9ff7c82653e/cryptography-46.0.7-cp314-cp314t-manylinux_2_28_aarch64.whl": "b7b412817be92117ec5ed95f880defe9cf18a832e8cafacf0a22337dc1981b4d", + "https://files.pythonhosted.org/packages/41/3d/fe14df95a83319af25717677e956567a105bb6ab25641acaa093db79975d/cryptography-46.0.7-cp314-cp314t-manylinux_2_34_ppc64le.whl": "c5b1ccd1239f48b7151a65bc6dd54bcfcc15e028c8ac126d3fada09db0e07ef1", + "https://files.pythonhosted.org/packages/41/52/a8908dcb1a389a459a29008c29966c1d552588d4ae6d43f3a1a4512e0ebe/cryptography-46.0.7-cp38-abi3-musllinux_1_2_x86_64.whl": "a1529d614f44b863a7b480c6d000fe93b59acee9c82ffa027cfadc77521a9f5e", + "https://files.pythonhosted.org/packages/47/93/ac8f3d5ff04d54bc814e961a43ae5b0b146154c89c61b47bb07557679b18/cryptography-46.0.7.tar.gz": "e4cfd68c5f3e0bfdad0d38e023239b96a2fe84146481852dffbcca442c245aa5", + "https://files.pythonhosted.org/packages/4a/9a/1765afe9f572e239c3469f2cb429f3ba7b31878c893b246b4b2994ffe2fe/cryptography-46.0.7-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl": "5ad9ef796328c5e3c4ceed237a183f5d41d21150f972455a9d926593a1dcb308", + "https://files.pythonhosted.org/packages/4b/fa/f0ab06238e899cc3fb332623f337a7364f36f4bb3f2534c2bb95a35b132c/cryptography-46.0.7-cp38-abi3-win32.whl": "f247c8c1a1fb45e12586afbb436ef21ff1e80670b2861a90353d9b025583d246", + "https://files.pythonhosted.org/packages/50/46/cf71e26025c2e767c5609162c866a78e8a2915bbcfa408b7ca495c6140c4/cryptography-46.0.7-cp314-cp314t-manylinux_2_28_ppc64le.whl": "fbfd0e5f273877695cb93baf14b185f4878128b250cc9f8e617ea0c025dfb022", + "https://files.pythonhosted.org/packages/59/6a/bb2e166d6d0e0955f1e9ff70f10ec4b2824c9cfcdb4da772c7dd69cc7d80/cryptography-46.0.7-cp314-cp314t-musllinux_1_2_x86_64.whl": "65814c60f8cc400c63131584e3e1fad01235edba2614b61fbfbfa954082db0ee", + "https://files.pythonhosted.org/packages/5f/45/6d80dc379b0bbc1f9d1e429f42e4cb9e1d319c7a8201beffd967c516ea01/cryptography-46.0.7-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl": "b36a4695e29fe69215d75960b22577197aca3f7a25b9cf9d165dcfe9d80bc325", + "https://files.pythonhosted.org/packages/63/0c/dca8abb64e7ca4f6b2978769f6fea5ad06686a190cec381f0a796fdcaaba/cryptography-46.0.7-pp311-pypy311_pp73-macosx_11_0_arm64.whl": "fc9ab8856ae6cf7c9358430e49b368f3108f050031442eaeb6b9d87e4dcf4e4f", + "https://files.pythonhosted.org/packages/69/33/60dfc4595f334a2082749673386a4d05e4f0cf4df8248e63b2c3437585f2/cryptography-46.0.7-cp311-abi3-manylinux_2_34_ppc64le.whl": "9694078c5d44c157ef3162e3bf3946510b857df5a3955458381d1c7cfc143ddb", + "https://files.pythonhosted.org/packages/6c/7b/1c55db7242b5e5612b29fc7a630e91ee7a6e3c8e7bf5406d22e206875fbd/cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl": "d02c738dacda7dc2a74d1b2b3177042009d5cab7c7079db74afc19e56ca1b455", + "https://files.pythonhosted.org/packages/74/66/e3ce040721b0b5599e175ba91ab08884c75928fbeb74597dd10ef13505d2/cryptography-46.0.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl": "db0f493b9181c7820c8134437eb8b0b4792085d37dbb24da050476ccb664e59c", + "https://files.pythonhosted.org/packages/7b/56/15619b210e689c5403bb0540e4cb7dbf11a6bf42e483b7644e471a2812b3/cryptography-46.0.7-cp314-cp314t-macosx_10_9_universal2.whl": "d151173275e1728cf7839aaa80c34fe550c04ddb27b34f48c232193df8db5842", + "https://files.pythonhosted.org/packages/80/07/ad9b3c56ebb95ed2473d46df0847357e01583f4c52a85754d1a55e29e4d0/cryptography-46.0.7-cp38-abi3-manylinux_2_34_ppc64le.whl": "935ce7e3cfdb53e3536119a542b839bb94ec1ad081013e9ab9b7cfd478b05006", + "https://files.pythonhosted.org/packages/8a/6c/1a42450f464dda6ffbe578a911f773e54dd48c10f9895a23a7e88b3e7db5/cryptography-46.0.7-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl": "128c5edfe5e5938b86b03941e94fac9ee793a94452ad1365c9fc3f4f62216832", + "https://files.pythonhosted.org/packages/8f/3e/af9246aaf23cd4ee060699adab1e47ced3f5f7e7a8ffdd339f817b446462/cryptography-46.0.7-cp311-abi3-manylinux_2_28_aarch64.whl": "73510b83623e080a2c35c62c15298096e2a5dc8d51c3b4e1740211839d0dea77", + "https://files.pythonhosted.org/packages/92/49/819d6ed3a7d9349c2939f81b500a738cb733ab62fbecdbc1e38e83d45e12/cryptography-46.0.7-cp38-abi3-manylinux_2_34_aarch64.whl": "abad9dac36cbf55de6eb49badd4016806b3165d396f64925bf2999bcb67837ba", + "https://files.pythonhosted.org/packages/95/b6/3da51d48415bcb63b00dc17c2eff3a651b7c4fed484308d0f19b30e8cb2c/cryptography-46.0.7-cp314-cp314t-win32.whl": "fdd1736fed309b4300346f88f74cd120c27c56852c3838cab416e7a166f67298", + "https://files.pythonhosted.org/packages/9a/92/4ed714dbe93a066dc1f4b4581a464d2d7dbec9046f7c8b7016f5286329e2/cryptography-46.0.7-cp38-abi3-manylinux_2_28_aarch64.whl": "5e51be372b26ef4ba3de3c167cd3d1022934bc838ae9eaad7e644986d2a3d163", + "https://files.pythonhosted.org/packages/9c/59/4a479e0f36f8f378d397f4eab4c850b4ffb79a2f0d58704b8fa0703ddc11/cryptography-46.0.7-cp314-cp314t-manylinux_2_34_x86_64.whl": "d5f7520159cd9c2154eb61eb67548ca05c5774d39e9c2c4339fd793fe7d097b2", + "https://files.pythonhosted.org/packages/a5/d0/36a49f0262d2319139d2829f773f1b97ef8aef7f97e6e5bd21455e5a8fb5/cryptography-46.0.7-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl": "84d4cced91f0f159a7ddacad249cc077e63195c36aac40b4150e7a57e84fffe7", + "https://files.pythonhosted.org/packages/a5/ef/649750cbf96f3033c3c976e112265c33906f8e462291a33d77f90356548c/cryptography-46.0.7-cp38-abi3-musllinux_1_2_aarch64.whl": "7bbc6ccf49d05ac8f7d7b5e2e2c33830d4fe2061def88210a126d130d7f71a85", + "https://files.pythonhosted.org/packages/a7/7f/cd42fc3614386bc0c12f0cb3c4ae1fc2bbca5c9662dfed031514911d513d/cryptography-46.0.7-cp38-abi3-macosx_10_9_universal2.whl": "462ad5cb1c148a22b2e3bcc5ad52504dff325d17daf5df8d88c17dda1f75f2a4", + "https://files.pythonhosted.org/packages/b5/2a/2ea0767cad19e71b3530e4cad9605d0b5e338b6a1e72c37c9c1ceb86c333/cryptography-46.0.7-cp314-cp314t-manylinux_2_34_aarch64.whl": "80406c3065e2c55d7f49a9550fe0c49b3f12e5bfff5dedb727e319e1afb9bf99", + "https://files.pythonhosted.org/packages/b7/e6/a26b84096eddd51494bba19111f8fffe976f6a09f132706f8f1bf03f51f7/cryptography-46.0.7-cp38-abi3-manylinux_2_28_ppc64le.whl": "cdf1a610ef82abb396451862739e3fc93b071c844399e15b90726ef7470eeaf2", + "https://files.pythonhosted.org/packages/b8/c7/201d3d58f30c4c2bdbe9b03844c291feb77c20511cc3586daf7edc12a47b/cryptography-46.0.7-cp38-abi3-manylinux_2_34_x86_64.whl": "35719dc79d4730d30f1c2b6474bd6acda36ae2dfae1e3c16f2051f215df33ce0", + "https://files.pythonhosted.org/packages/c0/ea/01276740375bac6249d0a971ebdf6b4dc9ead0ee0a34ef3b5a88c1a9b0d4/cryptography-46.0.7-cp314-cp314t-manylinux_2_28_x86_64.whl": "ffca7aa1d00cf7d6469b988c581598f2259e46215e0140af408966a24cf086ce", + "https://files.pythonhosted.org/packages/c7/08/ffd537b605568a148543ac3c2b239708ae0bd635064bab41359252ef88ed/cryptography-46.0.7-cp38-abi3-manylinux_2_28_x86_64.whl": "1d25aee46d0c6f1a501adcddb2d2fee4b979381346a78558ed13e50aa8a59067", + "https://files.pythonhosted.org/packages/c7/0b/333ddab4270c4f5b972f980adef4faa66951a4aaf646ca067af597f15563/cryptography-46.0.7-cp311-abi3-manylinux_2_34_x86_64.whl": "42a1e5f98abb6391717978baf9f90dc28a743b7d9be7f0751a6f56a75d14065b", + "https://files.pythonhosted.org/packages/cb/da/9870eec4b69c63ef5925bf7d8342b7e13bc2ee3d47791461c4e49ca212f4/cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl": "04959522f938493042d595a736e7dbdff6eb6cc2339c11465b3ff89343b65f65", + "https://files.pythonhosted.org/packages/d2/14/633913398b43b75f1234834170947957c6b623d1701ffc7a9600da907e89/cryptography-46.0.7-cp311-abi3-musllinux_1_2_aarch64.whl": "91bbcb08347344f810cbe49065914fe048949648f6bd5c2519f34619142bbe85", + "https://files.pythonhosted.org/packages/d2/f1/00ce3bde3ca542d1acd8f8cfa38e446840945aa6363f9b74746394b14127/cryptography-46.0.7-cp38-abi3-win_amd64.whl": "506c4ff91eff4f82bdac7633318a526b1d1309fc07ca76a3ad182cb5b686d6d3", + "https://files.pythonhosted.org/packages/f4/72/05aa5832b82dd341969e9a734d1812a6aadb088d9eb6f0430fc337cc5a8f/cryptography-46.0.7-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl": "3986ac1dee6def53797289999eabe84798ad7817f3e97779b5061a95b0ee4968", + "https://files.pythonhosted.org/packages/f9/46/4e4e9c6040fb01c7467d47217d2f882daddeb8828f7df800cb806d8a2288/cryptography-46.0.7-cp311-abi3-manylinux_2_31_armv7l.whl": "24402210aa54baae71d99441d15bb5a1919c195398a87b563df84468160a65de" + }, + "cssmin": { + "https://files.pythonhosted.org/packages/8e/d8/dc9da69bb186303f7ab41adef0a5b6d34da2fdba006827620877760241c3/cssmin-0.2.0.tar.gz": "e012f0cc8401efcf2620332339011564738ae32be8c84b2e43ce8beaec1067b6" + }, + "docutils": { + "https://files.pythonhosted.org/packages/02/10/5da547df7a391dcde17f59520a231527b8571e6f46fc8efb02ccb370ab12/docutils-0.22.4-py3-none-any.whl": "d0013f540772d1420576855455d050a2180186c91c15779301ac2ccb3eeb68de", + "https://files.pythonhosted.org/packages/4a/c0/89fe6215b443b919cb98a5002e107cb5026854ed1ccb6b5833e0768419d1/docutils-0.22.2.tar.gz": "9fdb771707c8784c8f2728b67cb2c691305933d68137ef95a75db5f4dfbc213d", + "https://files.pythonhosted.org/packages/66/dd/f95350e853a4468ec37478414fc04ae2d61dad7a947b3015c3dcc51a09b9/docutils-0.22.2-py3-none-any.whl": "b0e98d679283fc3bb0ead8a5da7f501baa632654e7056e9c5846842213d674d8", + "https://files.pythonhosted.org/packages/ae/b6/03bb70946330e88ffec97aefd3ea75ba575cb2e762061e0e62a213befee8/docutils-0.22.4.tar.gz": "4db53b1fde9abecbb74d91230d32ab626d94f6badfc575d6db9194a49df29968" + }, + "feedgenerator": { + "https://files.pythonhosted.org/packages/5e/4e/0efde53652edbae3f86c0ec67260bb53287edc67033ac8d00fe08cd02557/feedgenerator-2.1.0.tar.gz": "f075f23f28fd227f097c36b212161c6cf012e1c6caaf7ff53d5d6bb02cd42b9d", + "https://files.pythonhosted.org/packages/bd/a1/b7b1711d9bf43c3795366431633ab6ba6942744243aad809272ebfa59b39/feedgenerator-2.1.0-py3-none-any.whl": "93b7ce1c5a86195cafd6a8e9baf6a2a863ebd6d9905e840ce5778f73efd9a8d5" + }, + "idna": { + "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl": "946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", + "https://files.pythonhosted.org/packages/82/77/7b3966d0b9d1d31a36ddf1746926a11dface89a83409bf1483f0237aa758/idna-3.15.tar.gz": "ca962446ea538f7092a95e057da437618e886f4d349216d2b1e294abfdb65fdc", + "https://files.pythonhosted.org/packages/d2/23/408243171aa9aaba178d3e2559159c24c1171a641aa83b67bdd3394ead8e/idna-3.15-py3-none-any.whl": "048adeaf8c2d788c40fee287673ccaa74c24ffd8dcf09ffa555a2fbb59f10ac8", + "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz": "12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9" + }, + "importlib-metadata": { + "https://files.pythonhosted.org/packages/20/b0/36bd937216ec521246249be3bf9855081de4c5e06a0c9b4219dbeda50373/importlib_metadata-8.7.0-py3-none-any.whl": "e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd", + "https://files.pythonhosted.org/packages/76/66/650a33bd90f786193e4de4b3ad86ea60b53c89b669a5c7be931fac31cdb0/importlib_metadata-8.7.0.tar.gz": "d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000" + }, + "jaraco-classes": { + "https://files.pythonhosted.org/packages/06/c0/ed4a27bc5571b99e3cff68f8a9fa5b56ff7df1c2251cc715a652ddd26402/jaraco.classes-3.4.0.tar.gz": "47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd", + "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl": "f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790" + }, + "jaraco-context": { + "https://files.pythonhosted.org/packages/df/ad/f3777b81bf0b6e7bc7514a1656d3e637b2e8e15fab2ce3235730b3e7a4e6/jaraco_context-6.0.1.tar.gz": "9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3", + "https://files.pythonhosted.org/packages/ff/db/0c52c4cf5e4bd9f5d7135ec7669a3a767af21b3a308e1ed3674881e52b62/jaraco.context-6.0.1-py3-none-any.whl": "f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4" + }, + "jaraco-functools": { + "https://files.pythonhosted.org/packages/b4/09/726f168acad366b11e420df31bf1c702a54d373a83f968d94141a8c3fde0/jaraco_functools-4.3.0-py3-none-any.whl": "227ff8ed6f7b8f62c56deff101545fa7543cf2c8e7b82a7c2116e672f29c26e8", + "https://files.pythonhosted.org/packages/f7/ed/1aa2d585304ec07262e1a83a9889880701079dde796ac7b1d1826f40c63d/jaraco_functools-4.3.0.tar.gz": "cfd13ad0dd2c47a3600b439ef72d8615d482cedcff1632930d6f28924d92f294" + }, + "jeepney": { + "https://files.pythonhosted.org/packages/7b/6f/357efd7602486741aa73ffc0617fb310a29b588ed0fd69c2399acbb85b0c/jeepney-0.9.0.tar.gz": "cf0e9e845622b81e4a28df94c40345400256ec608d0e55bb8a3feaa9163f5732", + "https://files.pythonhosted.org/packages/b2/a3/e137168c9c44d18eff0376253da9f1e9234d0239e0ee230d2fee6cea8e55/jeepney-0.9.0-py3-none-any.whl": "97e5714520c16fc0a45695e5365a2e11b81ea79bba796e26f9f1d178cb182683" + }, + "jinja2": { + "https://files.pythonhosted.org/packages/20/9a/e5d9ec41927401e41aea8af6d16e78b5e612bca4699d417f646a9610a076/Jinja2-3.0.3-py3-none-any.whl": "077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8", + "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl": "85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", + "https://files.pythonhosted.org/packages/91/a5/429efc6246119e1e3fbf562c00187d04e83e54619249eb732bb423efa6c6/Jinja2-3.0.3.tar.gz": "611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7", + "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz": "0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d" + }, + "keyring": { + "https://files.pythonhosted.org/packages/70/09/d904a6e96f76ff214be59e7aa6ef7190008f52a0ab6689760a98de0bf37d/keyring-25.6.0.tar.gz": "0b39998aa941431eb3d9b0d4b2460bc773b9df6fed7621c2dfb291a7e0187a66", + "https://files.pythonhosted.org/packages/d3/32/da7f44bcb1105d3e88a0b74ebdca50c59121d2ddf71c9e34ba47df7f3a56/keyring-25.6.0-py3-none-any.whl": "552a3f7af126ece7ed5c89753650eec89c7eaae8617d0aa4d9ad2b75111266bd" + }, + "libsass": { + "https://files.pythonhosted.org/packages/55/2f/6af938651ff3aec0a0b00742209df1172bc297fa73531f292801693b7315/libsass-0.23.0-cp38-abi3-macosx_14_0_arm64.whl": "ea97d1b45cdc2fc3590cb9d7b60f1d8915d3ce17a98c1f2d4dd47ee0d9c68ce6", + "https://files.pythonhosted.org/packages/79/b4/ab091585eaa77299558e3289ca206846aefc123fb320b5656ab2542c20ad/libsass-0.23.0.tar.gz": "6f209955ede26684e76912caf329f4ccb57e4a043fd77fe0e7348dd9574f1880", + "https://files.pythonhosted.org/packages/e5/13/fc1bea1de880ca935137183727c7d4dd921c4128fc08b8ddc3698ba5a8a3/libsass-0.23.0-cp38-abi3-macosx_11_0_x86_64.whl": "34cae047cbbfc4ffa832a61cbb110f3c95f5471c6170c842d3fed161e40814dc", + "https://files.pythonhosted.org/packages/e5/fc/275783f5120970d859ae37d04b6a60c13bdec2aa4294b9dfa8a37b5c2513/libsass-0.23.0-cp38-abi3-win32.whl": "31e86d92a5c7a551df844b72d83fc2b5e50abc6fbbb31e296f7bebd6489ed1b4", + "https://files.pythonhosted.org/packages/ef/20/caf3c7cf2432d85263119798c45221ddf67bdd7dae8f626d14ff8db04040/libsass-0.23.0-cp38-abi3-win_amd64.whl": "a2ec85d819f353cbe807432d7275d653710d12b08ec7ef61c124a580a8352f3c", + "https://files.pythonhosted.org/packages/fd/5a/eb5b62641df0459a3291fc206cf5bd669c0feed7814dded8edef4ade8512/libsass-0.23.0-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.whl": "4a218406d605f325d234e4678bd57126a66a88841cb95bee2caeafdc6f138306" + }, + "markdown": { + "https://files.pythonhosted.org/packages/2b/f4/69fa6ed85ae003c2378ffa8f6d2e3234662abd02c10d216c0ba96081a238/markdown-3.10.2.tar.gz": "994d51325d25ad8aa7ce4ebaec003febcce822c3f8c911e3b17c52f7f589f950", + "https://files.pythonhosted.org/packages/de/1f/77fa3081e4f66ca3576c896ae5d31c3002ac6607f9747d2e3aa49227e464/markdown-3.10.2-py3-none-any.whl": "e91464b71ae3ee7afd3017d9f358ef0baf158fd9a298db92f1d4761133824c36" + }, + "markdown-it-py": { + "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz": "e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", + "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl": "355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", + "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz": "cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", + "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl": "87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147" + }, + "markupsafe": { + "https://files.pythonhosted.org/packages/00/0b/23f4b2470accb53285c613a3ab9ec19dc944eaf53592cb6d9e2af8aa24cc/MarkupSafe-2.1.5-cp311-cp311-win32.whl": "397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906", + "https://files.pythonhosted.org/packages/02/8c/ab9a463301a50dab04d5472e998acbd4080597abc048166ded5c7aa768c8/MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl": "5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6", + "https://files.pythonhosted.org/packages/0a/0d/2454f072fae3b5a137c119abf15465d1771319dfe9e4acbb31722a0fff91/MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl": "f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5", + "https://files.pythonhosted.org/packages/0a/7b/85681ae3c33c385b10ac0f8dd025c30af83c78cec1c37a6aa3b55e67f5ec/MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl": "e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46", + "https://files.pythonhosted.org/packages/0b/cc/48206bd61c5b9d0129f4d75243b156929b04c94c09041321456fd06a876d/MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl": "bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e", + "https://files.pythonhosted.org/packages/0c/40/2e73e7d532d030b1e41180807a80d564eda53babaf04d65e15c1cf897e40/MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl": "7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c", + "https://files.pythonhosted.org/packages/0e/7d/968284145ffd9d726183ed6237c77938c021abacde4e073020f920e060b2/MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl": "8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3", + "https://files.pythonhosted.org/packages/0f/31/780bb297db036ba7b7bbede5e1d7f1e14d704ad4beb3ce53fb495d22bc62/MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl": "7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf", + "https://files.pythonhosted.org/packages/11/e7/291e55127bb2ae67c64d66cef01432b5933859dfb7d6949daa721b89d0b3/MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl": "629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f", + "https://files.pythonhosted.org/packages/18/46/5dca760547e8c59c5311b332f70605d24c99d1303dd9a6e1fc3ed0d73561/MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl": "0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f", + "https://files.pythonhosted.org/packages/1c/cf/35fe557e53709e93feb65575c93927942087e9b97213eabc3fe9d5b25a55/MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl": "6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced", + "https://files.pythonhosted.org/packages/29/fe/a36ba8c7ca55621620b2d7c585313efd10729e63ef81e4e61f52330da781/MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl": "ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900", + "https://files.pythonhosted.org/packages/2d/75/fd6cb2e68780f72d47e6671840ca517bda5ef663d30ada7616b0462ad1e3/MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl": "ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b", + "https://files.pythonhosted.org/packages/2f/69/30d29adcf9d1d931c75001dd85001adad7374381c9c2086154d9f6445be6/MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl": "7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9", + "https://files.pythonhosted.org/packages/30/39/8d845dd7d0b0613d86e0ef89549bfb5f61ed781f59af45fc96496e897f3a/MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl": "fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd", + "https://files.pythonhosted.org/packages/3a/03/63498d05bd54278b6ca340099e5b52ffb9cdf2ee4f2d9b98246337e21689/MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl": "2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df", + "https://files.pythonhosted.org/packages/3f/14/c3554d512d5f9100a95e737502f4a2323a1959f6d0d01e0d0997b35f7b10/MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl": "823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb", + "https://files.pythonhosted.org/packages/48/d6/e7cd795fc710292c3af3a06d80868ce4b02bfbbf370b7cee11d282815a2a/MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl": "3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4", + "https://files.pythonhosted.org/packages/4a/1d/c4f5016f87ced614eacc7d5fb85b25bcc0ff53e8f058d069fc8cbfdc3c7a/MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl": "a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a", + "https://files.pythonhosted.org/packages/4c/6f/f2b0f675635b05f6afd5ea03c094557bdb8622fa8e673387444fe8d8e787/MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl": "ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68", + "https://files.pythonhosted.org/packages/4f/14/6f294b9c4f969d0c801a4615e221c1e084722ea6114ab2114189c5b8cbe0/MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl": "97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46", + "https://files.pythonhosted.org/packages/51/b5/5d8ec796e2a08fc814a2c7d2584b55f889a55cf17dd1a90f2beb70744e5c/MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl": "ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee", + "https://files.pythonhosted.org/packages/51/e0/393467cf899b34a9d3678e78961c2c8cdf49fb902a959ba54ece01273fb1/MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl": "5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0", + "https://files.pythonhosted.org/packages/53/bd/583bf3e4c8d6a321938c13f49d44024dbe5ed63e0a7ba127e454a66da974/MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl": "8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1", + "https://files.pythonhosted.org/packages/5f/5a/360da85076688755ea0cceb92472923086993e86b5613bbae9fbc14136b0/MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl": "17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3", + "https://files.pythonhosted.org/packages/60/ae/9c60231cdfda003434e8bd27282b1f4e197ad5a710c14bee8bea8a9ca4f0/MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl": "075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff", + "https://files.pythonhosted.org/packages/65/dc/1510be4d179869f5dafe071aecb3f1f41b45d37c02329dfba01ff59e5ac5/MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl": "598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad", + "https://files.pythonhosted.org/packages/68/79/11b4fe15124692f8673b603433e47abca199a08ecd2a4851bfbdc97dc62d/MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl": "ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50", + "https://files.pythonhosted.org/packages/69/48/acbf292615c65f0604a0c6fc402ce6d8c991276e16c80c46a8f758fbd30c/MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl": "bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5", + "https://files.pythonhosted.org/packages/6a/18/ae5a258e3401f9b8312f92b028c54d7026a97ec3ab20bfaddbdfa7d8cce8/MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl": "4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465", + "https://files.pythonhosted.org/packages/6a/4a/a4d49415e600bacae038c67f9fecc1d5433b9d3c71a4de6f33537b89654c/MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl": "72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5", + "https://files.pythonhosted.org/packages/6b/cb/aed7a284c00dfa7c0682d14df85ad4955a350a21d2e3b06d8240497359bf/MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl": "5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2", + "https://files.pythonhosted.org/packages/6c/4c/3577a52eea1880538c435176bc85e5b3379b7ab442327ccd82118550758f/MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl": "4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2", + "https://files.pythonhosted.org/packages/6c/77/d77701bbef72892affe060cdacb7a2ed7fd68dae3b477a8642f15ad3b132/MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl": "db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2", + "https://files.pythonhosted.org/packages/6d/c5/27febe918ac36397919cd4a67d5579cbbfa8da027fa1238af6285bb368ea/MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl": "c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a", + "https://files.pythonhosted.org/packages/7c/52/2b1b570f6b8b803cef5ac28fdf78c0da318916c7d2fe9402a84d591b394c/MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl": "2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f", + "https://files.pythonhosted.org/packages/81/d4/fd74714ed30a1dedd0b82427c02fa4deec64f173831ec716da11c51a50aa/MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl": "1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532", + "https://files.pythonhosted.org/packages/87/5b/aae44c6655f3801e81aa3eef09dbbf012431987ba564d7231722f68df02d/MarkupSafe-2.1.5.tar.gz": "d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b", + "https://files.pythonhosted.org/packages/88/07/2dc76aa51b481eb96a4c3198894f38b480490e834479611a4053fbf08623/MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl": "58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169", + "https://files.pythonhosted.org/packages/8b/ff/9a52b71839d7a256b563e85d11050e307121000dcebc97df120176b3ad93/MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl": "bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f", + "https://files.pythonhosted.org/packages/92/21/357205f03514a49b293e214ac39de01fadd0970a6e05e4bf1ddd0ffd0881/MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl": "619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029", + "https://files.pythonhosted.org/packages/96/0c/620c1fb3661858c0e37eb3cbffd8c6f732a67cd97296f725789679801b31/MarkupSafe-2.1.5-cp312-cp312-win32.whl": "8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad", + "https://files.pythonhosted.org/packages/97/18/c30da5e7a0e7f4603abfc6780574131221d9148f323752c2755d48abad30/MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl": "b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5", + "https://files.pythonhosted.org/packages/a7/88/a940e11827ea1c136a34eca862486178294ae841164475b9ab216b80eb8e/MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl": "c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f", + "https://files.pythonhosted.org/packages/b0/81/147c477391c2750e8fc7705829f7351cf1cd3be64406edcf900dc633feb2/MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl": "d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a", + "https://files.pythonhosted.org/packages/b3/fb/c18b8c9fbe69e347fdbf782c6478f1bc77f19a830588daa224236678339b/MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl": "4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52", + "https://files.pythonhosted.org/packages/b7/a2/c78a06a9ec6d04b3445a949615c4c7ed86a0b2eb68e44e7541b9d57067cc/MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl": "2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617", + "https://files.pythonhosted.org/packages/bc/29/9bc18da763496b055d8e98ce476c8e718dcfd78157e17f555ce6dd7d0895/MarkupSafe-2.1.5-cp39-cp39-win32.whl": "00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf", + "https://files.pythonhosted.org/packages/bf/f3/ecb00fc8ab02b7beae8699f34db9357ae49d9f21d4d3de6f305f34fa949e/MarkupSafe-2.1.5-cp38-cp38-win32.whl": "daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff", + "https://files.pythonhosted.org/packages/c7/5c/356a6f62e4f3c5fbf2602b4771376af22a3b16efa74eb8716fb4e328e01e/MarkupSafe-2.1.5-cp310-cp310-win32.whl": "d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4", + "https://files.pythonhosted.org/packages/c7/bd/50319665ce81bb10e90d1cf76f9e1aa269ea6f7fa30ab4521f14d122a3df/MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl": "fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab", + "https://files.pythonhosted.org/packages/cb/06/0d28bd178db529c5ac762a625c335a9168a7a23f280b4db9c95e97046145/MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl": "ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf", + "https://files.pythonhosted.org/packages/d1/06/a41c112ab9ffdeeb5f77bc3e331fdadf97fa65e52e44ba31880f4e7f983c/MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl": "bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea", + "https://files.pythonhosted.org/packages/d9/a7/1e558b4f78454c8a3a0199292d96159eb4d091f983bc35ef258314fe7269/MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl": "3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8", + "https://files.pythonhosted.org/packages/e4/54/ad5eb37bf9d51800010a74e4665425831a9db4e7c4e0fde4352e391e808e/MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl": "a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc", + "https://files.pythonhosted.org/packages/ed/88/408bdbf292eb86f03201c17489acafae8358ba4e120d92358308c15cea7c/MarkupSafe-2.1.5-cp37-cp37m-win32.whl": "4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371", + "https://files.pythonhosted.org/packages/f6/02/5437e2ad33047290dafced9df741d9efc3e716b75583bbd73a9984f1b6f7/MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl": "30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4", + "https://files.pythonhosted.org/packages/f6/f8/4da07de16f10551ca1f640c92b5f316f9394088b183c6a57183df6de5ae4/MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl": "fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5", + "https://files.pythonhosted.org/packages/f8/81/56e567126a2c2bc2684d6391332e357589a96a76cb9f8e5052d85cb0ead8/MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl": "3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f", + "https://files.pythonhosted.org/packages/f8/ff/2c942a82c35a49df5de3a630ce0a8456ac2969691b230e530ac12314364c/MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl": "656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a" + }, + "mdurl": { + "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl": "84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", + "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz": "bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba" + }, + "more-itertools": { + "https://files.pythonhosted.org/packages/a4/8e/469e5a4a2f5855992e425f3cb33804cc07bf18d48f2db061aec61ce50270/more_itertools-10.8.0-py3-none-any.whl": "52d4362373dcf7c52546bc4af9a86ee7c4579df9a8dc268be0a2f949d376cc9b", + "https://files.pythonhosted.org/packages/ea/5d/38b681d3fce7a266dd9ab73c66959406d565b3e85f21d5e66e1181d93721/more_itertools-10.8.0.tar.gz": "f638ddf8a1a0d134181275fb5d58b086ead7c6a72429ad725c67503f13ba30bd" + }, + "nh3": { + "https://files.pythonhosted.org/packages/0c/e0/cf1543e798ba86d838952e8be4cb8d18e22999be2a24b112a671f1c04fd6/nh3-0.3.0-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl": "ec6cfdd2e0399cb79ba4dcffb2332b94d9696c52272ff9d48a630c5dca5e325a", + "https://files.pythonhosted.org/packages/10/71/2fb1834c10fab6d9291d62c95192ea2f4c7518bd32ad6c46aab5d095cb87/nh3-0.3.0-cp313-cp313t-musllinux_1_2_i686.whl": "0649464ac8eee018644aacbc103874ccbfac80e3035643c3acaab4287e36e7f5", + "https://files.pythonhosted.org/packages/23/1e/80a8c517655dd40bb13363fc4d9e66b2f13245763faab1a20f1df67165a7/nh3-0.3.0-cp313-cp313t-win_amd64.whl": "423201bbdf3164a9e09aa01e540adbb94c9962cc177d5b1cbb385f5e1e79216e", + "https://files.pythonhosted.org/packages/2f/d6/f1c6e091cbe8700401c736c2bc3980c46dca770a2cf6a3b48a175114058e/nh3-0.3.0-cp313-cp313t-win32.whl": "7275fdffaab10cc5801bf026e3c089d8de40a997afc9e41b981f7ac48c5aa7d5", + "https://files.pythonhosted.org/packages/33/c1/8f8ccc2492a000b6156dce68a43253fcff8b4ce70ab4216d08f90a2ac998/nh3-0.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl": "1adeb1062a1c2974bc75b8d1ecb014c5fd4daf2df646bbe2831f7c23659793f9", + "https://files.pythonhosted.org/packages/39/2c/6394301428b2017a9d5644af25f487fa557d06bc8a491769accec7524d9a/nh3-0.3.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl": "f416c35efee3e6a6c9ab7716d9e57aa0a49981be915963a82697952cba1353e1", + "https://files.pythonhosted.org/packages/4c/3c/cba7b26ccc0ef150c81646478aa32f9c9535234f54845603c838a1dc955c/nh3-0.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl": "80fe20171c6da69c7978ecba33b638e951b85fb92059259edd285ff108b82a6d", + "https://files.pythonhosted.org/packages/4e/9a/344b9f9c4bd1c2413a397f38ee6a3d5db30f1a507d4976e046226f12b297/nh3-0.3.0-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl": "37d3003d98dedca6cd762bf88f2e70b67f05100f6b949ffe540e189cc06887f9", + "https://files.pythonhosted.org/packages/5b/76/3165e84e5266d146d967a6cc784ff2fbf6ddd00985a55ec006b72bc39d5d/nh3-0.3.0-cp38-abi3-win_arm64.whl": "d97d3efd61404af7e5721a0e74d81cdbfc6e5f97e11e731bb6d090e30a7b62b2", + "https://files.pythonhosted.org/packages/5c/86/a96b1453c107b815f9ab8fac5412407c33cc5c7580a4daf57aabeb41b774/nh3-0.3.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl": "ce5e7185599f89b0e391e2f29cc12dc2e206167380cea49b33beda4891be2fe1", + "https://files.pythonhosted.org/packages/63/da/c5fd472b700ba37d2df630a9e0d8cc156033551ceb8b4c49cc8a5f606b68/nh3-0.3.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl": "ba0caa8aa184196daa6e574d997a33867d6d10234018012d35f86d46024a2a95", + "https://files.pythonhosted.org/packages/66/3f/cd37f76c8ca277b02a84aa20d7bd60fbac85b4e2cbdae77cb759b22de58b/nh3-0.3.0-cp38-abi3-musllinux_1_2_aarch64.whl": "634e34e6162e0408e14fb61d5e69dbaea32f59e847cfcfa41b66100a6b796f62", + "https://files.pythonhosted.org/packages/6a/1b/b15bd1ce201a1a610aeb44afd478d55ac018b4475920a3118ffd806e2483/nh3-0.3.0-cp38-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl": "e9e6a7e4d38f7e8dda9edd1433af5170c597336c1a74b4693c5cb75ab2b30f2a", + "https://files.pythonhosted.org/packages/8c/ae/324b165d904dc1672eee5f5661c0a68d4bab5b59fbb07afb6d8d19a30b45/nh3-0.3.0-cp38-abi3-win_amd64.whl": "bae63772408fd63ad836ec569a7c8f444dd32863d0c67f6e0b25ebbd606afa95", + "https://files.pythonhosted.org/packages/8f/14/079670fb2e848c4ba2476c5a7a2d1319826053f4f0368f61fca9bb4227ae/nh3-0.3.0-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl": "7852f038a054e0096dac12b8141191e02e93e0b4608c4b993ec7d4ffafea4e49", + "https://files.pythonhosted.org/packages/97/03/03f79f7e5178eb1ad5083af84faff471e866801beb980cc72943a4397368/nh3-0.3.0-cp38-abi3-musllinux_1_2_i686.whl": "c7a32a7f0d89f7d30cb8f4a84bdbd56d1eb88b78a2434534f62c71dac538c450", + "https://files.pythonhosted.org/packages/97/33/11e7273b663839626f714cb68f6eb49899da5a0d9b6bc47b41fe870259c2/nh3-0.3.0-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl": "389d93d59b8214d51c400fb5b07866c2a4f79e4e14b071ad66c92184fec3a392", + "https://files.pythonhosted.org/packages/9a/e0/af86d2a974c87a4ba7f19bc3b44a8eaa3da480de264138fec82fe17b340b/nh3-0.3.0-cp313-cp313t-win_arm64.whl": "16f8670201f7e8e0e05ed1a590eb84bfa51b01a69dd5caf1d3ea57733de6a52f", + "https://files.pythonhosted.org/packages/a3/e5/ac7fc565f5d8bce7f979d1afd68e8cb415020d62fa6507133281c7d49f91/nh3-0.3.0-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl": "af5aa8127f62bbf03d68f67a956627b1bd0469703a35b3dad28d0c1195e6c7fb", + "https://files.pythonhosted.org/packages/ad/7f/7c6b8358cf1222921747844ab0eef81129e9970b952fcb814df417159fb9/nh3-0.3.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl": "7c915060a2c8131bef6a29f78debc29ba40859b6dbe2362ef9e5fd44f11487c2", + "https://files.pythonhosted.org/packages/b4/11/340b7a551916a4b2b68c54799d710f86cf3838a4abaad8e74d35360343bb/nh3-0.3.0-cp313-cp313t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl": "a537ece1bf513e5a88d8cff8a872e12fe8d0f42ef71dd15a5e7520fecd191bbb", + "https://files.pythonhosted.org/packages/c3/a4/96cff0977357f60f06ec4368c4c7a7a26cccfe7c9fcd54f5378bf0428fd3/nh3-0.3.0.tar.gz": "d8ba24cb31525492ea71b6aac11a4adac91d828aadeff7c4586541bf5dc34d2f", + "https://files.pythonhosted.org/packages/c9/50/76936ec021fe1f3270c03278b8af5f2079038116b5d0bfe8538ffe699d69/nh3-0.3.0-cp38-abi3-win32.whl": "6d68fa277b4a3cf04e5c4b84dd0c6149ff7d56c12b3e3fab304c525b850f613d", + "https://files.pythonhosted.org/packages/ce/55/1974bcc16884a397ee699cebd3914e1f59be64ab305533347ca2d983756f/nh3-0.3.0-cp38-abi3-musllinux_1_2_x86_64.whl": "3f1b4f8a264a0c86ea01da0d0c390fe295ea0bcacc52c2103aca286f6884f518", + "https://files.pythonhosted.org/packages/ee/db/7aa11b44bae4e7474feb1201d8dee04fabe5651c7cb51409ebda94a4ed67/nh3-0.3.0-cp38-abi3-musllinux_1_2_armv7l.whl": "b0612ccf5de8a480cf08f047b08f9d3fecc12e63d2ee91769cb19d7290614c23", + "https://files.pythonhosted.org/packages/f3/ba/59e204d90727c25b253856e456ea61265ca810cda8ee802c35f3fadaab00/nh3-0.3.0-cp313-cp313t-musllinux_1_2_armv7l.whl": "e90883f9f85288f423c77b3f5a6f4486375636f25f793165112679a7b6363b35" + }, + "ordered-set": { + "https://files.pythonhosted.org/packages/33/55/af02708f230eb77084a299d7b08175cff006dea4f2721074b92cdb0296c0/ordered_set-4.1.0-py3-none-any.whl": "046e1132c71fcf3330438a539928932caf51ddbc582496833e23de611de14562", + "https://files.pythonhosted.org/packages/4c/ca/bfac8bc689799bcca4157e0e0ced07e70ce125193fc2e166d2e685b7e2fe/ordered-set-4.1.0.tar.gz": "694a8e44c87657c59292ede72891eb91d34131f6531463aab3009191c77364a8" + }, + "packaging": { + "https://files.pythonhosted.org/packages/d7/f1/e7a6dd94a8d4a5626c03e4e99c87f241ba9e350cd9e6d75123f992427270/packaging-26.2.tar.gz": "ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661", + "https://files.pythonhosted.org/packages/df/b2/87e62e8c3e2f4b32e5fe99e0b86d576da1312593b39f47d8ceef365e95ed/packaging-26.2-py3-none-any.whl": "5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e" + }, + "pelican": { + "https://files.pythonhosted.org/packages/6e/55/4adcce41a45f8f77e69d7e84ea447819dae1a78b4b9762a104599e5ec811/pelican-4.12.0-py3-none-any.whl": "3697230f56cfcca9e98d3ac9ac26f655bb20cad807f7eacf156601e241f69ad8", + "https://files.pythonhosted.org/packages/c4/8d/da26b77f0d9827d341bdedea357ccb5670717e3a9b4142e3e44c7f34db44/pelican-4.12.0.tar.gz": "3983b5d2dc84c7bdf967154359077a2b78c0bbd2f7dcc55292133a7779609458" + }, + "pelican-webassets": { + "https://files.pythonhosted.org/packages/42/d6/844e251c8da875d6ff4a86715394f43f8ad2141d70577f7e77e4058576b2/pelican_webassets-2.1.0-py3-none-any.whl": "9df6659ecb565af88df55df4aac27cafc948299ef3d4fc743f7385db2e274475", + "https://files.pythonhosted.org/packages/a1/22/6241f976879780ec6f89bf45df36952169f305cdddbaabcba2ae797e699e/pelican_webassets-2.1.0.tar.gz": "0a418b88ebd6d96efae4d666394552bcacc8d30d2f0abb5bb4db26064e8cfed0" + }, + "pkginfo": { + "https://files.pythonhosted.org/packages/24/03/e26bf3d6453b7fda5bd2b84029a426553bb373d6277ef6b5ac8863421f87/pkginfo-1.12.1.2.tar.gz": "5cd957824ac36f140260964eba3c6be6442a8359b8c48f4adf90210f33a04b7b", + "https://files.pythonhosted.org/packages/fa/3d/f4f2ba829efb54b6cd2d91349c7463316a9cc55a43fc980447416c88540f/pkginfo-1.12.1.2-py3-none-any.whl": "c783ac885519cab2c34927ccfa6bf64b5a704d7c69afaea583dd9b7afe969343" + }, + "pycparser": { + "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl": "e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", + "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz": "78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2" + }, + "pygments": { + "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz": "636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", + "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl": "86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b" + }, + "python-dateutil": { + "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz": "37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", + "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl": "a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427" + }, + "pytz": { + "https://files.pythonhosted.org/packages/ec/dd/96da98f892250475bdf2328112d7468abdd4acc7b902b6af23f4ed958ea0/pytz-2026.2-py2.py3-none-any.whl": "04156e608bee23d3792fd45c94ae47fae1036688e75032eea2e3bf0323d1f126", + "https://files.pythonhosted.org/packages/ff/46/dd499ec9038423421951e4fad73051febaa13d2df82b4064f87af8b8c0c3/pytz-2026.2.tar.gz": "0e60b47b29f21574376f218fe21abc009894a2321ea16c6754f3cad6eb7cdd6a" + }, + "pywin32-ctypes": { + "https://files.pythonhosted.org/packages/85/9f/01a1a99704853cb63f253eea009390c88e7131c67e66a0a02099a8c917cb/pywin32-ctypes-0.2.3.tar.gz": "d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755", + "https://files.pythonhosted.org/packages/de/3d/8161f7711c017e01ac9f008dfddd9410dff3674334c233bde66e7ba65bbf/pywin32_ctypes-0.2.3-py3-none-any.whl": "8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8" + }, + "pyyaml": { + "https://files.pythonhosted.org/packages/02/72/d972384252432d57f248767556ac083793292a4adf4e2d85dfe785ec2659/PyYAML-6.0.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl": "9c57bb8c96f6d1808c030b1687b9b5fb476abaa47f0db9c0101f5e9f394e97f4", + "https://files.pythonhosted.org/packages/02/9e/e5e9b168be58564121efb3de6859c452fccde0ab093d8438905899a3a483/pyyaml-6.0.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl": "b3bc83488de33889877a0f2543ade9f70c67d66d9ebb4ac959502e12de895788", + "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl": "02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", + "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz": "d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", + "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl": "8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", + "https://files.pythonhosted.org/packages/0c/62/d2eb46264d4b157dae1275b573017abec435397aa59cbcdab6fc978a8af4/pyyaml-6.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl": "10892704fc220243f5305762e276552a0395f7beb4dbf9b14ec8fd43b57f126c", + "https://files.pythonhosted.org/packages/0d/a2/09f67a3589cb4320fb5ce90d3fd4c9752636b8b6ad8f34b54d76c5a54693/PyYAML-6.0.3-cp38-cp38-macosx_10_13_x86_64.whl": "c2514fceb77bc5e7a2f7adfaa1feb2fb311607c9cb518dbc378688ec73d8292f", + "https://files.pythonhosted.org/packages/10/cb/16c3f2cf3266edd25aaa00d6c4350381c8b012ed6f5276675b9eba8d9ff4/pyyaml-6.0.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl": "850774a7879607d3a6f50d36d04f00ee69e7fc816450e5f7e58d7f17f1ae5c00", + "https://files.pythonhosted.org/packages/16/19/13de8e4377ed53079ee996e1ab0a9c33ec2faf808a4647b7b4c0d46dd239/pyyaml-6.0.3-cp311-cp311-macosx_11_0_arm64.whl": "652cb6edd41e718550aad172851962662ff2681490a8a711af6a4d288dd96824", + "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl": "64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", + "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl": "5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", + "https://files.pythonhosted.org/packages/23/20/bb6982b26a40bb43951265ba29d4c246ef0ff59c9fdcdf0ed04e0687de4d/pyyaml-6.0.3-cp314-cp314-win_amd64.whl": "4a2e8cebe2ff6ab7d1050ecd59c25d4c8bd7e6f400f5f82b96557ac0abafd0ac", + "https://files.pythonhosted.org/packages/25/a2/b725b61ac76a75583ae7104b3209f75ea44b13cfd026aa535ece22b7f22e/PyYAML-6.0.3-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl": "22ba7cfcad58ef3ecddc7ed1db3409af68d023b7f940da23c6c2a1890976eda6", + "https://files.pythonhosted.org/packages/29/3d/6f5e0d58bd924fb0d06c3a6bad00effbdae2de5adb5cda5648006ffbd8d3/pyyaml-6.0.3-cp39-cp39-win32.whl": "1ebe39cb5fc479422b83de611d14e2c0d3bb2a18bbcb01f229ab3cfbd8fee7a0", + "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl": "bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", + "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl": "66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", + "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl": "eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", + "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl": "b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", + "https://files.pythonhosted.org/packages/45/91/47a6e1c42d9ee337c4839208f30d9f09caa9f720ec7582917b264defc875/pyyaml-6.0.3-cp311-cp311-win32.whl": "8098f252adfa6c80ab48096053f512f2321f0b998f98150cea9bd23d83e1467b", + "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl": "a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", + "https://files.pythonhosted.org/packages/4e/78/8d08c9fb7ce09ad8c38ad533c1191cf27f7ae1effe5bb9400a46d9437fcf/pyyaml-6.0.3-cp314-cp314t-macosx_11_0_arm64.whl": "c1ff362665ae507275af2853520967820d9124984e0f7466736aea23d8611fba", + "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl": "ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", + "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl": "5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", + "https://files.pythonhosted.org/packages/6d/16/a95b6757765b7b031c9374925bb718d55e0a9ba8a1b6a12d25962ea44347/pyyaml-6.0.3-cp311-cp311-macosx_10_13_x86_64.whl": "44edc647873928551a01e7a563d7452ccdebee747728c1080d881d68af7b997e", + "https://files.pythonhosted.org/packages/6f/b0/b2227677b2d1036d84f5ee95eb948e7af53d59fe3e4328784e4d290607e0/PyYAML-6.0.3-cp38-cp38-musllinux_1_2_x86_64.whl": "6344df0d5755a2c9a276d4473ae6b90647e216ab4757f8426893b5dd2ac3f369", + "https://files.pythonhosted.org/packages/71/60/917329f640924b18ff085ab889a11c763e0b573da888e8404ff486657602/pyyaml-6.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl": "b8bb0864c5a28024fac8a632c443c87c5aa6f215c0b126c449ae1a150412f31d", + "https://files.pythonhosted.org/packages/73/b9/793686b2d54b531203c160ef12bec60228a0109c79bae6c1277961026770/pyyaml-6.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl": "0150219816b6a1fa26fb4699fb7daa9caf09eb1999f3b70fb6e786805e80375a", + "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl": "5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", + "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl": "0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", + "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl": "96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", + "https://files.pythonhosted.org/packages/76/b2/2b69cee94c9eb215216fc05778675c393e3aa541131dc910df8e52c83776/PyYAML-6.0.3-cp38-cp38-win_amd64.whl": "5cf4e27da7e3fbed4d6c3d8e797387aaad68102272f8f9752883bc32d61cb87b", + "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl": "9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", + "https://files.pythonhosted.org/packages/7b/5b/3babb19104a46945cf816d047db2788bcaf8c94527a805610b0289a01c6b/pyyaml-6.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl": "6adc77889b628398debc7b65c073bcb99c4a0237b248cacaf3fe8a557563ef6c", + "https://files.pythonhosted.org/packages/7c/f9/07dd09ae774e4616edf6cda684ee78f97777bdd15847253637a6f052a62f/pyyaml-6.0.3-cp314-cp314t-macosx_10_13_x86_64.whl": "02893d100e99e03eda1c8fd5c441d8c60103fd175728e23e431db1b589cf5ab3", + "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl": "5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", + "https://files.pythonhosted.org/packages/88/f9/16491d7ed2a919954993e48aa941b200f38040928474c9e85ea9e64222c3/pyyaml-6.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl": "c458b6d084f9b935061bc36216e8a69a7e293a2f1e68bf956dcd9e6cbcd143f5", + "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl": "fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", + "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl": "ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", + "https://files.pythonhosted.org/packages/8b/cc/dff0684d8dc44da4d22a13f35f073d558c268780ce3c6ba1b87055bb0b87/pyyaml-6.0.3-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl": "a80cb027f6b349846a3bf6d73b5e95e782175e52f22108cfa17876aaeff93702", + "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl": "418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", + "https://files.pythonhosted.org/packages/92/b5/47e807c2623074914e29dabd16cbbdd4bf5e9b2db9f8090fa64411fc5382/pyyaml-6.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl": "501a031947e3a9025ed4405a168e6ef5ae3126c59f90ce0cd6f2bfc477be31b7", + "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl": "79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", + "https://files.pythonhosted.org/packages/99/a5/718a8ea22521e06ef19f91945766a892c5ceb1855df6adbde67d997ea7ed/PyYAML-6.0.3-cp38-cp38-win32.whl": "3ff07ec89bae51176c0549bc4c63aa6202991da2d9a6129d7aef7f1407d3f295", + "https://files.pythonhosted.org/packages/9d/8c/f4bd7f6465179953d3ac9bc44ac1a8a3e6122cf8ada906b4f96c60172d43/pyyaml-6.0.3-cp314-cp314-macosx_10_13_x86_64.whl": "8d1fab6bb153a416f9aeb4b8763bc0f22a5586065f86f7664fc23339fc1c1fac", + "https://files.pythonhosted.org/packages/9f/62/67fc8e68a75f738c9200422bf65693fb79a4cd0dc5b23310e5202e978090/pyyaml-6.0.3-cp39-cp39-macosx_10_13_x86_64.whl": "b865addae83924361678b652338317d1bd7e79b1f4596f96b96c77a5a34b34da", + "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl": "28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", + "https://files.pythonhosted.org/packages/a7/3b/6c58ac0fa7c4e1b35e48024eb03d00817438310447f93ef4431673c24138/PyYAML-6.0.3-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl": "efd7b85f94a6f21e4932043973a7ba2613b059c4a000551892ac9f1d11f5baf3", + "https://files.pythonhosted.org/packages/a9/86/a137b39a611def2ed78b0e66ce2fe13ee701a07c07aebe55c340ed2a050e/pyyaml-6.0.3-cp39-cp39-musllinux_1_2_aarch64.whl": "fa160448684b4e94d80416c0fa4aac48967a969efe22931448d853ada8baf926", + "https://files.pythonhosted.org/packages/ae/92/861f152ce87c452b11b9d0977952259aa7df792d71c1053365cc7b09cc08/pyyaml-6.0.3-cp39-cp39-macosx_11_0_arm64.whl": "c3355370a2c156cffb25e876646f149d5d68f5e0a3ce86a5084dd0b64a994917", + "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl": "2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", + "https://files.pythonhosted.org/packages/b1/5e/f77dc6b9036943e285ba76b49e118d9ea929885becb0a29ba8a7c75e29fe/pyyaml-6.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl": "00c4bdeba853cc34e7dd471f16b4114f4162dc03e6b7afcc2128711f0eca823c", + "https://files.pythonhosted.org/packages/bd/9c/4d95bb87eb2063d20db7b60faa3840c1b18025517ae857371c4dd55a6b3a/pyyaml-6.0.3-cp314-cp314-macosx_11_0_arm64.whl": "34d5fcd24b8445fadc33f9cf348c1047101756fd760b4dacb5c3e99755703310", + "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl": "41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", + "https://files.pythonhosted.org/packages/ce/88/a9db1376aa2a228197c58b37302f284b5617f56a5d959fd1763fb1675ce6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl": "66e1674c3ef6f541c35191caae2d429b967b99e02040f5ba928632d9a7f0f065", + "https://files.pythonhosted.org/packages/d0/cd/f0cfc8c74f8a030017a2b9c771b7f47e5dd702c3e28e5b2071374bda2948/pyyaml-6.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl": "3c5677e12444c15717b902a5798264fa7909e41153cdf9ef7ad571b704a63dd9", + "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl": "8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", + "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl": "7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", + "https://files.pythonhosted.org/packages/d7/ce/af88a49043cd2e265be63d083fc75b27b6ed062f5f9fd6cdc223ad62f03e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_x86_64.whl": "5190d403f121660ce8d1d2c1bb2ef1bd05b5f68533fc5c2ea899bd15f4399b35", + "https://files.pythonhosted.org/packages/da/92/1446574745d74df0c92e6aa4a7b0b3130706a4142b2d1a5869f2eaa423c6/pyyaml-6.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl": "16249ee61e95f858e83976573de0f5b2893b3677ba71c9dd36b9cf8be9ac6d65", + "https://files.pythonhosted.org/packages/da/e3/ea007450a105ae919a72393cb06f122f288ef60bba2dc64b26e2646fa315/pyyaml-6.0.3-cp311-cp311-win_amd64.whl": "9f3bfb4965eb874431221a3ff3fdcddc7e74e3b07799e0e84ca4a0f867d449bf", + "https://files.pythonhosted.org/packages/dd/3f/5989debef34dc6397317802b527dbbafb2b4760878a53d4166579111411e/pyyaml-6.0.3-cp314-cp314-musllinux_1_2_aarch64.whl": "7c6610def4f163542a622a73fb39f534f8c101d690126992300bf3207eab9764", + "https://files.pythonhosted.org/packages/dd/62/71c27c94f457cf4418ef8ccc71735324c549f7e3ea9d34aba50874563561/pyyaml-6.0.3-cp39-cp39-musllinux_1_2_x86_64.whl": "27c0abcb4a5dac13684a37f76e701e054692a9b2d3064b70f5e4eb54810553d7", + "https://files.pythonhosted.org/packages/dd/6f/529b0f316a9fd167281a6c3826b5583e6192dba792dd55e3203d3f8e655a/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_aarch64.whl": "1d37d57ad971609cf3c53ba6a7e365e40660e3be0e5175fa9f2365a379d6095a", + "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl": "d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", + "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl": "9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", + "https://files.pythonhosted.org/packages/ef/b2/18f2bd28cd2055a79a46c9b0895c0b3d987ce40ee471cecf58a1a0199805/pyyaml-6.0.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl": "5ed875a24292240029e4483f9d4a4b8a1ae08843b9c54f43fcc11e404532a8a5", + "https://files.pythonhosted.org/packages/f0/0c/25113e0b5e103d7f1490c0e947e303fe4a696c10b501dea7a9f49d4e876c/pyyaml-6.0.3-cp39-cp39-win_amd64.whl": "2e71d11abed7344e42a8849600193d15b6def118602c4c176f748e4583246007", + "https://files.pythonhosted.org/packages/f0/7a/1c7270340330e575b92f397352af856a8c06f230aa3e76f86b39d01b416a/pyyaml-6.0.3-cp314-cp314t-win_amd64.whl": "4ad1906908f2f5ae4e5a8ddfce73c320c2a1429ec52eafd27138b7f1cbe341c9", + "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl": "ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", + "https://files.pythonhosted.org/packages/f2/6a/b627b4e0c1dd03718543519ffb2f1deea4a1e6d42fbab8021936a4d22589/pyyaml-6.0.3-cp311-cp311-musllinux_1_2_x86_64.whl": "37503bfbfc9d2c40b344d06b2199cf0e96e97957ab1c1b546fd4f87e53e5d3e4", + "https://files.pythonhosted.org/packages/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl": "214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", + "https://files.pythonhosted.org/packages/f4/f4/a4541072bb9422c8a883ab55255f918fa378ecf083f5b85e87fc2b4eda1b/pyyaml-6.0.3-cp314-cp314-win_arm64.whl": "93dda82c9c22deb0a405ea4dc5f2d0cda384168e466364dec6255b293923b2f3", + "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl": "f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6" + }, + "readme-renderer": { + "https://files.pythonhosted.org/packages/5a/a9/104ec9234c8448c4379768221ea6df01260cd6c2ce13182d4eac531c8342/readme_renderer-44.0.tar.gz": "8712034eabbfa6805cacf1402b4eeb2a73028f72d1166d6f5cb7f9c047c5d1e1", + "https://files.pythonhosted.org/packages/e1/67/921ec3024056483db83953ae8e48079ad62b92db7880013ca77632921dd0/readme_renderer-44.0-py3-none-any.whl": "2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151" + }, + "requests": { + "https://files.pythonhosted.org/packages/34/64/8860370b167a9721e8956ae116825caff829224fbca0ca6e7bf8ddef8430/requests-2.33.0.tar.gz": "c7ebc5e8b0f21837386ad0e1c8fe8b829fa5f544d8df3b2253bff14ef29d7652", + "https://files.pythonhosted.org/packages/56/5d/c814546c2333ceea4ba42262d8c4d55763003e767fa169adc693bd524478/requests-2.33.0-py3-none-any.whl": "3324635456fa185245e24865e810cecec7b4caf933d7eb133dcde67d48cee69b" + }, + "requests-toolbelt": { + "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl": "cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06", + "https://files.pythonhosted.org/packages/f3/61/d7545dafb7ac2230c70d38d31cbfe4cc64f7144dc41f6e4e4b78ecd9f5bb/requests-toolbelt-1.0.0.tar.gz": "7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6" + }, + "rfc3986": { + "https://files.pythonhosted.org/packages/85/40/1520d68bfa07ab5a6f065a186815fb6610c86fe957bc065754e47f7b0840/rfc3986-2.0.0.tar.gz": "97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c", + "https://files.pythonhosted.org/packages/ff/9a/9afaade874b2fa6c752c36f1548f718b5b83af81ed9b76628329dab81c1b/rfc3986-2.0.0-py2.py3-none-any.whl": "50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd" + }, + "rich": { + "https://files.pythonhosted.org/packages/87/67/a37f6214d0e9fe57f6ae54b2956d550ca8365857f42a1ce0392bb21d9410/rich-13.7.1-py3-none-any.whl": "4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222", + "https://files.pythonhosted.org/packages/b3/01/c954e134dc440ab5f96952fe52b4fdc64225530320a910473c1fe270d9aa/rich-13.7.1.tar.gz": "9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432", + "https://files.pythonhosted.org/packages/e3/30/3c4d035596d3cf444529e0b2953ad0466f6049528a879d27534700580395/rich-14.1.0-py3-none-any.whl": "536f5f1785986d6dbdea3c75205c473f970777b4a0d6c6dd1b696aa05a3fa04f", + "https://files.pythonhosted.org/packages/fe/75/af448d8e52bf1d8fa6a9d089ca6c07ff4453d86c65c145d0a300bb073b9b/rich-14.1.0.tar.gz": "e497a48b844b0320d45007cdebfeaeed8db2a4f4bcf49f15e455cfc4af11eaa8" + }, + "secretstorage": { + "https://files.pythonhosted.org/packages/53/a4/f48c9d79cb507ed1373477dbceaba7401fd8a23af63b837fa61f1dcd3691/SecretStorage-3.3.3.tar.gz": "2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77", + "https://files.pythonhosted.org/packages/54/24/b4293291fa1dd830f353d2cb163295742fa87f179fcc8a20a306a81978b7/SecretStorage-3.3.3-py3-none-any.whl": "f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99" + }, + "six": { + "https://files.pythonhosted.org/packages/71/39/171f1c67cd00715f190ba0b100d606d440a28c93c7714febeca8b79af85e/six-1.16.0.tar.gz": "1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", + "https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl": "8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + }, + "sniffio": { + "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz": "f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", + "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl": "2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2" + }, + "twine": { + "https://files.pythonhosted.org/packages/5d/ec/00f9d5fd040ae29867355e559a94e9a8429225a0284a3f5f091a3878bfc0/twine-5.1.1-py3-none-any.whl": "215dbe7b4b94c2c50a7315c0275d2258399280fbb7d04182c7e55e24b5f93997", + "https://files.pythonhosted.org/packages/77/68/bd982e5e949ef8334e6f7dcf76ae40922a8750aa2e347291ae1477a4782b/twine-5.1.1.tar.gz": "9aa0825139c02b3434d913545c7b847a21c835e11597f5255842d457da2322db" + }, + "unidecode": { + "https://files.pythonhosted.org/packages/84/b7/6ec57841fb67c98f52fc8e4a2d96df60059637cba077edc569a302a8ffc7/Unidecode-1.3.8-py3-none-any.whl": "d130a61ce6696f8148a3bd8fe779c99adeb4b870584eeb9526584e9aa091fd39", + "https://files.pythonhosted.org/packages/f7/89/19151076a006b9ac0dd37b1354e031f5297891ee507eb624755e58e10d3e/Unidecode-1.3.8.tar.gz": "cfdb349d46ed3873ece4586b96aa75258726e2fa8ec21d6f00a591d98806c2f4" + }, + "urllib3": { + "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl": "bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", + "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz": "1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed" + }, + "watchfiles": { + "https://files.pythonhosted.org/packages/00/24/1c089457e39a0e6a142df8cb795a690b71f05c948bc60df4ec12359956b8/watchfiles-0.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl": "fd257f98cff9c6cb39eee1a83c7c3183970d8a8d23e8cf4f47d9a21329285cee", + "https://files.pythonhosted.org/packages/03/31/c1b5ea92100d9774f5a8a89115a43ef1c4fb169b643b6cc930e0cd2c5728/watchfiles-0.23.0-cp311-none-win_amd64.whl": "46f1d8069a95885ca529645cdbb05aea5837d799965676e1b2b1f95a4206313e", + "https://files.pythonhosted.org/packages/03/f1/fdacfdbffb0635a7d0140ecca6ef7b5bce6566a085f76a65eb796ee54ddd/watchfiles-0.23.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl": "0e01bcb8d767c58865207a6c2f2792ad763a0fe1119fb0a430f444f5b02a5ea0", + "https://files.pythonhosted.org/packages/06/9c/46e0d17853b62b5d4bf8095e7b9bb0b0ad4babb6c6133138929473f161f3/watchfiles-0.23.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl": "b8d3c5cd327dd6ce0edfc94374fb5883d254fe78a5e9d9dfc237a1897dc73cd1", + "https://files.pythonhosted.org/packages/07/85/0d231295071443fb82f2d57a786ae9b2d935c7a168724b74a8de0c07d53e/watchfiles-0.23.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl": "a96ac14e184aa86dc43b8a22bb53854760a58b2966c2b41580de938e9bf26ed0", + "https://files.pythonhosted.org/packages/09/47/8287b6757a094988eb762837a8ad814525c966c2d156cd0e486d1d6ac8d5/watchfiles-0.23.0-cp39-cp39-musllinux_1_1_aarch64.whl": "8ada449e22198c31fb013ae7e9add887e8d2bd2335401abd3cbc55f8c5083647", + "https://files.pythonhosted.org/packages/09/79/f9e6dca8a48766f3186b9610f77055f80e81fd5cb2371c55d13d6a84d19e/watchfiles-0.23.0-pp38-pypy38_pp73-macosx_10_12_x86_64.whl": "aba037c1310dd108411d27b3d5815998ef0e83573e47d4219f45753c710f969f", + "https://files.pythonhosted.org/packages/0b/07/f5b54afa8b7c33386c5778d92e681562939900f4ee1c6de9bffc49e7221f/watchfiles-0.23.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl": "02b7ba9d4557149410747353e7325010d48edcfe9d609a85cb450f17fd50dc3d", + "https://files.pythonhosted.org/packages/14/5f/787386438d895145099e1415d1fbd3ff047a4f5e329134fd30677fe83f1f/watchfiles-0.23.0-cp311-cp311-macosx_10_12_x86_64.whl": "e397b64f7aaf26915bf2ad0f1190f75c855d11eb111cc00f12f97430153c2eab", + "https://files.pythonhosted.org/packages/1a/c6/bf3b8cbe6944499fbe0d400175560a200cdecadccbacc8ace74486565d74/watchfiles-0.23.0-cp313-none-win_amd64.whl": "f449afbb971df5c6faeb0a27bca0427d7b600dd8f4a068492faec18023f0dcff", + "https://files.pythonhosted.org/packages/1d/b9/09e6918eac8d6f9e178adfa8b99b4f955001e670086cf4778e4e1daf973e/watchfiles-0.23.0-cp38-none-win_amd64.whl": "c846884b2e690ba62a51048a097acb6b5cd263d8bd91062cd6137e2880578472", + "https://files.pythonhosted.org/packages/20/08/c0a09fc63a6b75fccd3e99b21f07ddb812e64a78da10703397b39653263e/watchfiles-0.23.0-cp310-cp310-macosx_10_12_x86_64.whl": "bee8ce357a05c20db04f46c22be2d1a2c6a8ed365b325d08af94358e0688eeb4", + "https://files.pythonhosted.org/packages/20/5e/a97417a6544615b21c7960a45aeea13e3b42779e0ed3ebdd2d76ad62ab50/watchfiles-0.23.0-cp312-cp312-macosx_11_0_arm64.whl": "62d2b18cb1edaba311fbbfe83fb5e53a858ba37cacb01e69bc20553bb70911b8", + "https://files.pythonhosted.org/packages/22/ec/c756c012b174ccf5f2ee32202603e66b33b93a54cf16c69a7440c764d7f9/watchfiles-0.23.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl": "8f48c917ffd36ff9a5212614c2d0d585fa8b064ca7e66206fb5c095015bc8207", + "https://files.pythonhosted.org/packages/22/ee/06a0a6cbde8ac6fff57c33da9e428f42dd0989e60a6ad72ca6534f650a47/watchfiles-0.23.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl": "37fd826dac84c6441615aa3f04077adcc5cac7194a021c9f0d69af20fb9fa788", + "https://files.pythonhosted.org/packages/23/9c/810ede8d4dff7e65393b50cbb1a3ef10b6cdb1312a97d8106712175355c8/watchfiles-0.23.0-cp311-none-win_arm64.whl": "e495ed2a7943503766c5d1ff05ae9212dc2ce1c0e30a80d4f0d84889298fa304", + "https://files.pythonhosted.org/packages/28/24/060b064f28083866d916052fcced5c3547c5081a8e27b0702434666aa9a0/watchfiles-0.23.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl": "dd41d5c72417b87c00b1b635738f3c283e737d75c5fa5c3e1c60cd03eac3af77", + "https://files.pythonhosted.org/packages/28/8a/6d00aa4aa9a9938de645c1d411e3af82e74db8d25a0c05427b7a88b4d8d3/watchfiles-0.23.0-cp313-cp313-musllinux_1_1_aarch64.whl": "109a61763e7318d9f821b878589e71229f97366fa6a5c7720687d367f3ab9eef", + "https://files.pythonhosted.org/packages/29/46/f41defd581154c4022c04ef41f812e6fd1633e75444e7b12147fdb0b7364/watchfiles-0.23.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl": "7ca6b71dcc50d320c88fb2d88ecd63924934a8abc1673683a242a7ca7d39e781", + "https://files.pythonhosted.org/packages/2c/35/a683945181a527083a1146620997b5d6ffe06d716c4497d388bfea813f0c/watchfiles-0.23.0-cp312-cp312-musllinux_1_1_x86_64.whl": "bd3e2d64500a6cad28bcd710ee6269fbeb2e5320525acd0cfab5f269ade68581", + "https://files.pythonhosted.org/packages/2c/ff/e891b230bcf3a648352a00b920d4a1142a938f0b97c9e8e27c2eaaeda221/watchfiles-0.23.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl": "9ff785af8bacdf0be863ec0c428e3288b817e82f3d0c1d652cd9c6d509020dd0", + "https://files.pythonhosted.org/packages/2f/bd/6ac26a36b16182e2b6df21ac7a86c647979ae43acb6dd03eab14bee66bd8/watchfiles-0.23.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl": "1733b9bc2c8098c6bdb0ff7a3d7cb211753fecb7bd99bdd6df995621ee1a574b", + "https://files.pythonhosted.org/packages/32/17/819ab060ff4f948c419d0d6e3a7c3d49bc19e6b75fc9afeb155395049d7a/watchfiles-0.23.0-cp38-cp38-macosx_10_12_x86_64.whl": "2dddc2487d33e92f8b6222b5fb74ae2cfde5e8e6c44e0248d24ec23befdc5366", + "https://files.pythonhosted.org/packages/34/2c/c279de01628f467d16b444bdcedf9c4ce3bc5242cb23f9bfb8fbff8522ee/watchfiles-0.23.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl": "d1aa4cc85202956d1a65c88d18c7b687b8319dbe6b1aec8969784ef7a10e7d1a", + "https://files.pythonhosted.org/packages/39/ba/d361135dac6cd0fb4449f4f058c053eb9b42f70ff4d9a13767808e18851c/watchfiles-0.23.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl": "c5e7803a65eb2d563c73230e9d693c6539e3c975ccfe62526cadde69f3fda0cf", + "https://files.pythonhosted.org/packages/3b/25/ec3676b140a93ac256d058a6f82810cf5e0e42fd444b948c62bc56f57f52/watchfiles-0.23.0-cp313-none-win32.whl": "f46c6f0aec8d02a52d97a583782d9af38c19a29900747eb048af358a9c1d8e5b", + "https://files.pythonhosted.org/packages/3b/cc/85dac96249b3fb93178d8111befed7ab517bdabec9793296c39400189235/watchfiles-0.23.0-cp38-none-win32.whl": "aafea64a3ae698695975251f4254df2225e2624185a69534e7fe70581066bc1b", + "https://files.pythonhosted.org/packages/3d/02/f223537cd0e3c22df45629710b27b7f89fdf4114be2f3399b83faedf1446/watchfiles-0.23.0-cp311-none-win32.whl": "1d636c8aeb28cdd04a4aa89030c4b48f8b2954d8483e5f989774fa441c0ed57b", + "https://files.pythonhosted.org/packages/3f/b5/1faa511755b72dfd0eecf2230113a55318e11d2080f659326e7f758b3b0f/watchfiles-0.23.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl": "532e1f2c491274d1333a814e4c5c2e8b92345d41b12dc806cf07aaff786beb66", + "https://files.pythonhosted.org/packages/43/cf/747f412b75ea4bb5419e659ae8b2713a327b6f879e3f2e0695c7d7275cf3/watchfiles-0.23.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl": "fb02d41c33be667e6135e6686f1bb76104c88a312a18faa0ef0262b5bf7f1a0f", + "https://files.pythonhosted.org/packages/4b/d1/dab28bed3bc9172d44100e5fae8107bd01ef85fc6bddb80d223d0d9f709f/watchfiles-0.23.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl": "6b1a950ab299a4a78fd6369a97b8763732bfb154fdb433356ec55a5bce9515c1", + "https://files.pythonhosted.org/packages/4b/dd/fab40f60fcfd868e000315983b996a97bb12977f2de347c1e7a40a5d1c7d/watchfiles-0.23.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl": "f18de0f82c62c4197bea5ecf4389288ac755896aac734bd2cc44004c56e4ac47", + "https://files.pythonhosted.org/packages/54/29/e5052c455ff0d8fa9625b99b11877f804bb68150d2c8b82a4b2d871fd23d/watchfiles-0.23.0-cp39-none-win_amd64.whl": "d2d42254b189a346249424fb9bb39182a19289a2409051ee432fb2926bad966a", + "https://files.pythonhosted.org/packages/57/65/f3e854c5b8912d76c8fefc7c891b3df628b9110907b968faadcb8142347e/watchfiles-0.23.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl": "18e2de19801b0eaa4c5292a223effb7cfb43904cb742c5317a0ac686ed604765", + "https://files.pythonhosted.org/packages/5a/d9/120d212d2952342e2c9673096f5c17cd48e90a7c9ff203ab1ad2f974befe/watchfiles-0.23.0-cp313-cp313-musllinux_1_1_x86_64.whl": "9f8e6bb5ac007d4a4027b25f09827ed78cbbd5b9700fd6c54429278dacce05d1", + "https://files.pythonhosted.org/packages/5c/25/6511ed7bc826ddc2a4e879cf469621a1184719e97d63e7f723e95991ebd3/watchfiles-0.23.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl": "9f02a259fcbbb5fcfe7a0805b1097ead5ba7a043e318eef1db59f93067f0b49b", + "https://files.pythonhosted.org/packages/5e/7f/bdf0d159141d2926432331a0eb33ae2a4978b9ad89912ce9297711cbc43e/watchfiles-0.23.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl": "a8f195338a5a7b50a058522b39517c50238358d9ad8284fd92943643144c0c03", + "https://files.pythonhosted.org/packages/61/52/85cdf326a53f1ae3fbe5dcab13f5729ca91ec2d61140e095a2a4cdf6a9ca/watchfiles-0.23.0-cp312-cp312-macosx_10_12_x86_64.whl": "1db691bad0243aed27c8354b12d60e8e266b75216ae99d33e927ff5238d270b5", + "https://files.pythonhosted.org/packages/62/c9/94f91ad2f88f4d84a0ccea6628d47f51007f03d5e4be6718f208c55cd1f5/watchfiles-0.23.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl": "02ff5d7bd066c6a7673b17c8879cd8ee903078d184802a7ee851449c43521bdd", + "https://files.pythonhosted.org/packages/67/38/6a24bf5724ce3d6e9087a7f9b7faf33760dfa5616974eda1ed35ba9ef41b/watchfiles-0.23.0-cp39-cp39-macosx_11_0_arm64.whl": "6bb91fa4d0b392f0f7e27c40981e46dda9eb0fbc84162c7fb478fe115944f491", + "https://files.pythonhosted.org/packages/6a/a1/d7aa3f23c78b2c9cac5d1cf46fed5f74340d0ffd47c0f485b76419ec6597/watchfiles-0.23.0-cp310-none-win_amd64.whl": "4ea756e425ab2dfc8ef2a0cb87af8aa7ef7dfc6fc46c6f89bcf382121d4fff75", + "https://files.pythonhosted.org/packages/73/d3/00d561a66aa000251ed598f576e8bfd1c4102f9956fc06310e9b53258d3e/watchfiles-0.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl": "1ebaebb53b34690da0936c256c1cdb0914f24fb0e03da76d185806df9328abed", + "https://files.pythonhosted.org/packages/76/6f/3075cd9c69fdce2544fb13cb9e3c8ad51424cb2c552b019514799a14966e/watchfiles-0.23.0-cp311-cp311-macosx_11_0_arm64.whl": "b4ac73b02ca1824ec0a7351588241fd3953748d3774694aa7ddb5e8e46aef3e3", + "https://files.pythonhosted.org/packages/78/94/97ac8d7a19f5439ab5cc28d0b5d648760358e43097f6acb8cb7165c4c1b7/watchfiles-0.23.0-cp310-cp310-musllinux_1_1_aarch64.whl": "9d183e3888ada88185ab17064079c0db8c17e32023f5c278d7bf8014713b1b5b", + "https://files.pythonhosted.org/packages/8c/ff/2b338016e96ab592e8d9cece0260b9fca54d8bed7b36940c46112eda2e49/watchfiles-0.23.0-cp310-cp310-macosx_11_0_arm64.whl": "4ccd3011cc7ee2f789af9ebe04745436371d36afe610028921cab9f24bb2987b", + "https://files.pythonhosted.org/packages/91/6c/f099be35e763bae70190c8b9ce269f94745cb181711bdf023c1f1796a9f0/watchfiles-0.23.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl": "efadd40fca3a04063d40c4448c9303ce24dd6151dc162cfae4a2a060232ebdcb", + "https://files.pythonhosted.org/packages/93/41/dcfbc67472a42480f4376124b52238cc8b6b84d9b2b0316cc037feaa4b22/watchfiles-0.23.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl": "20b423b58f5fdde704a226b598a2d78165fe29eb5621358fe57ea63f16f165c4", + "https://files.pythonhosted.org/packages/98/e1/76ad010c0a2bb6efbb80383c0bba56db065238f12b0da6e6026b4e69f6aa/watchfiles-0.23.0-cp313-cp313-macosx_11_0_arm64.whl": "85042ab91814fca99cec4678fc063fb46df4cbb57b4835a1cc2cb7a51e10250e", + "https://files.pythonhosted.org/packages/9e/1a/b06613ef620d7f5ca712a3d4928ec1c07182159a64277fcdf7738edb0b32/watchfiles-0.23.0.tar.gz": "9338ade39ff24f8086bb005d16c29f8e9f19e55b18dcb04dfa26fcbc09da497b", + "https://files.pythonhosted.org/packages/9e/9b/ec2eabc996e5332fc89c633fbe762e08a58a7df6b5e595dd458c5f7778a4/watchfiles-0.23.0-cp312-none-win32.whl": "eb99c954291b2fad0eff98b490aa641e128fbc4a03b11c8a0086de8b7077fb75", + "https://files.pythonhosted.org/packages/a1/13/d2d59d545b84fd3cf4f08b69da358209b4276c2c932d060d94a421015074/watchfiles-0.23.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl": "24655e8c1c9c114005c3868a3d432c8aa595a786b8493500071e6a52f3d09217", + "https://files.pythonhosted.org/packages/a1/2c/0d86bd0b9239f7d72f96848357eb082baed2d70b5cc257593d1ad39e06cd/watchfiles-0.23.0-cp38-cp38-musllinux_1_1_x86_64.whl": "a8323daae27ea290ba3350c70c836c0d2b0fb47897fa3b0ca6a5375b952b90d3", + "https://files.pythonhosted.org/packages/a3/b6/243c1dd351ac9b8258a3ea99c33d04ecdc9766e6c7f13a43452883e92a7a/watchfiles-0.23.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl": "48a1b05c0afb2cd2f48c1ed2ae5487b116e34b93b13074ed3c22ad5c743109f0", + "https://files.pythonhosted.org/packages/a4/9f/a3c9f1fbcd1099554e4f707e14473ff23f0e05013d553755b98c2d86716d/watchfiles-0.23.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl": "87f889f6e58849ddb7c5d2cb19e2e074917ed1c6e3ceca50405775166492cca8", + "https://files.pythonhosted.org/packages/a4/b8/992e478c6732ab75bf97d691f2ae7bf9f0aac4e269b2ac776ed79a65ef3a/watchfiles-0.23.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl": "ee1f5fcbf5bc33acc0be9dd31130bcba35d6d2302e4eceafafd7d9018c7755ab", + "https://files.pythonhosted.org/packages/ab/6b/cd4faa27088a8b612ffdfa25e3d413e676a6173b8b02a33e7fec152d75ca/watchfiles-0.23.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl": "130a896d53b48a1cecccfa903f37a1d87dbb74295305f865a3e816452f6e49e4", + "https://files.pythonhosted.org/packages/ae/8d/fdf4efc0235dcf158e8e1e91a3f74ff2db7492c94397cdba463c0e5e6293/watchfiles-0.23.0-cp39-cp39-musllinux_1_1_x86_64.whl": "3af1b05361e1cc497bf1be654a664750ae61f5739e4bb094a2be86ec8c6db9b6", + "https://files.pythonhosted.org/packages/b0/c5/d6a3c0001e116063b85382308770eaf2235decd2fbae3c67178e45fc07b0/watchfiles-0.23.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl": "524fcb8d59b0dbee2c9b32207084b67b2420f6431ed02c18bd191e6c575f5c48", + "https://files.pythonhosted.org/packages/b1/32/86f0d012d344168ed30746c04cac7ce3292ef5220fa4823ad73ca5f1f1db/watchfiles-0.23.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl": "b1f67312efa3902a8e8496bfa9824d3bec096ff83c4669ea555c6bdd213aa516", + "https://files.pythonhosted.org/packages/b1/64/a80f51cb55c967629930682bf120d5ca9d1c65077c38328be635ed0d567c/watchfiles-0.23.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl": "7f7252f52a09f8fa5435dc82b6af79483118ce6bd51eb74e6269f05ee22a7b9f", + "https://files.pythonhosted.org/packages/b3/e4/2647ca9aaa072e139a4cc6c83c8a15d2f8fa6740913903ab998917a5ed97/watchfiles-0.23.0-cp311-cp311-musllinux_1_1_x86_64.whl": "857af85d445b9ba9178db95658c219dbd77b71b8264e66836a6eba4fbf49c320", + "https://files.pythonhosted.org/packages/b4/45/d97e61c893fc59d4b0c4154fdf26449e103a3783db4d981bb8e7301af532/watchfiles-0.23.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl": "ecf2be4b9eece4f3da8ba5f244b9e51932ebc441c0867bd6af46a3d97eb068d6", + "https://files.pythonhosted.org/packages/b4/dd/8214a88b94fd0ed559e3f38b973a01bb3b48e9365dcb1d1966438dce816d/watchfiles-0.23.0-cp39-cp39-macosx_10_12_x86_64.whl": "a753993635eccf1ecb185dedcc69d220dab41804272f45e4aef0a67e790c3eb3", + "https://files.pythonhosted.org/packages/b6/00/ac760f3fa8d8975dbeaef9af99b21077e7c38898ac5051c8601649d86d99/watchfiles-0.23.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl": "1e5f3ca0ff47940ce0a389457b35d6df601c317c1e1a9615981c474452f98de1", + "https://files.pythonhosted.org/packages/b9/f0/76ad5227da9461b1190de2f9dd21fece09660a9a44607de9c728f3d3e93f/watchfiles-0.23.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl": "ee7db6e36e7a2c15923072e41ea24d9a0cf39658cb0637ecc9307b09d28827e1", + "https://files.pythonhosted.org/packages/bc/82/537945ed624af6248c9820a99cbfd5902bb5e6a71a01a5b3de0c00f1872e/watchfiles-0.23.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl": "e087e8fdf1270d000913c12e6eca44edd02aad3559b3e6b8ef00f0ce76e0636f", + "https://files.pythonhosted.org/packages/c4/ee/6fc9552ad1a68e68ea8209166916dc8c5824bef80c325ec36c5362277d24/watchfiles-0.23.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl": "556347b0abb4224c5ec688fc58214162e92a500323f50182f994f3ad33385dcb", + "https://files.pythonhosted.org/packages/c6/64/07f4c50883f1406e5a4187651b4d3d2495582df9f70d320ee3c9e7ed19be/watchfiles-0.23.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl": "7cf12ac34c444362f3261fb3ff548f0037ddd4c5bb85f66c4be30d2936beb3c5", + "https://files.pythonhosted.org/packages/ca/da/dffc4fc9a38a0189c91c502856d7d828b8ad6ecdecbeeb81022b301b5b03/watchfiles-0.23.0-cp38-cp38-musllinux_1_1_aarch64.whl": "0eff099a4df36afaa0eea7a913aa64dcf2cbd4e7a4f319a73012210af4d23810", + "https://files.pythonhosted.org/packages/d1/23/89b2bef692c350de8a4c2bde501fdf6087889a55f52a3201f0c53b616087/watchfiles-0.23.0-cp312-cp312-musllinux_1_1_aarch64.whl": "8e56fbcdd27fce061854ddec99e015dd779cae186eb36b14471fc9ae713b118c", + "https://files.pythonhosted.org/packages/d3/aa/33c470ba209a236865a6a6cc0c027e5b9e08b3420a3fb431e17c6d981fe1/watchfiles-0.23.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl": "b98732ec893975455708d6fc9a6daab527fc8bbe65be354a3861f8c450a632a4", + "https://files.pythonhosted.org/packages/d6/8b/8f868c420aa6afb19a40c20c2bceef879bf45b15c67a9d9b8ddb9cf28365/watchfiles-0.23.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl": "2537ef60596511df79b91613a5bb499b63f46f01a11a81b0a2b0dedf645d0a9c", + "https://files.pythonhosted.org/packages/d7/34/606577c1c99ed184edda555ce37728f6f3da90865e4dcfd98020c1f23fc1/watchfiles-0.23.0-cp39-none-win32.whl": "486bda18be5d25ab5d932699ceed918f68eb91f45d018b0343e3502e52866e5e", + "https://files.pythonhosted.org/packages/d8/e9/4af3cfb2eb161003ce79518eb0cbfd014313e30dc842209776fbee3a64e6/watchfiles-0.23.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl": "a0b2c25040a3c0ce0e66c7779cc045fdfbbb8d59e5aabfe033000b42fe44b53e", + "https://files.pythonhosted.org/packages/e0/3a/62add8d90070f4b17f8bbfd66c9eaa9e08af3bc4020c07a9400d1b959aaf/watchfiles-0.23.0-cp312-none-win_amd64.whl": "dccc858372a56080332ea89b78cfb18efb945da858fabeb67f5a44fa0bcb4ebb", + "https://files.pythonhosted.org/packages/e1/15/daf4361e0a6e6b27f516aaaacbb16baa8d1a266657b2314862fc73f2deaf/watchfiles-0.23.0-cp311-cp311-musllinux_1_1_aarch64.whl": "2368c5371c17fdcb5a2ea71c5c9d49f9b128821bfee69503cc38eae00feb3220", + "https://files.pythonhosted.org/packages/e4/63/9c5c902a041d4b742ab83220137e9c7570a829db6b0a9a41b751ac5937d0/watchfiles-0.23.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl": "1cf7f486169986c4b9d34087f08ce56a35126600b6fef3028f19ca16d5889071", + "https://files.pythonhosted.org/packages/e8/9a/2792d4c24105104bfaf959bffefb09e02d14050913a83242ce4eb1e3f2ff/watchfiles-0.23.0-cp312-none-win_arm64.whl": "6c21a5467f35c61eafb4e394303720893066897fca937bade5b4f5877d350ff8", + "https://files.pythonhosted.org/packages/ec/bf/77bc430ede44c217f3e6a68c1f55a8304dc1cd82d32623cacaedc2e122b2/watchfiles-0.23.0-cp38-cp38-macosx_11_0_arm64.whl": "e75695cc952e825fa3e0684a7f4a302f9128721f13eedd8dbd3af2ba450932b8", + "https://files.pythonhosted.org/packages/f2/55/7266cd63e736abbde902cbd99fb70a8eddfac7e0e52ed52fbbee6eed5f95/watchfiles-0.23.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl": "40cb8fa00028908211eb9f8d47744dca21a4be6766672e1ff3280bee320436f1", + "https://files.pythonhosted.org/packages/f6/5b/1a1d9bca4eae8cf191e74b62cd970f4a010f56f897c11dd2e6caef3ce7e3/watchfiles-0.23.0-cp313-cp313-macosx_10_12_x86_64.whl": "ba31c32f6b4dceeb2be04f717811565159617e28d61a60bb616b6442027fd4b9", + "https://files.pythonhosted.org/packages/f7/52/2f7bbedc5f524d2ba0e9d792dab01ef4418d0f5045a9f5f4e5aca142a30d/watchfiles-0.23.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl": "6991e3a78f642368b8b1b669327eb6751439f9f7eaaa625fae67dd6070ecfa0b", + "https://files.pythonhosted.org/packages/f7/7c/135a60260dd055227eb3b38f0be5fc16409ad58c5c6636467b27991fd863/watchfiles-0.23.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl": "6a9265cf87a5b70147bfb2fec14770ed5b11a5bb83353f0eee1c25a81af5abfe", + "https://files.pythonhosted.org/packages/fa/2c/ba3e9d54c17a4014996555a0b31f4be1c8920fdfe067942f60873ac8931a/watchfiles-0.23.0-cp310-none-win32.whl": "296e0b29ab0276ca59d82d2da22cbbdb39a23eed94cca69aed274595fb3dfe42", + "https://files.pythonhosted.org/packages/fc/c9/568a54e07245a068819572a7d51c7d2f6ff8e7018102e956156fadae408c/watchfiles-0.23.0-cp310-cp310-musllinux_1_1_x86_64.whl": "9837edf328b2805346f91209b7e660f65fb0e9ca18b7459d075d58db082bf981", + "https://files.pythonhosted.org/packages/fd/36/bf01f9d2f16609f8a9564c9001895df821212a14cda6e1cc25d4295c8c61/watchfiles-0.23.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl": "2aec5c29915caf08771d2507da3ac08e8de24a50f746eb1ed295584ba1820330", + "https://files.pythonhosted.org/packages/fd/df/af2a1c7b19eb4927bcd7edf75ed64ed6eb7208921adc14a11cdede1b3225/watchfiles-0.23.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl": "11698bb2ea5e991d10f1f4f83a39a02f91e44e4bd05f01b5c1ec04c9342bf63c" + }, + "zipp": { + "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl": "071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", + "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz": "a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166" + } + } + }, + "fact_version": "v1" } - } + }, + "factsVersions": {} } diff --git a/bazel/pgp/BUILD b/bazel/pgp/BUILD new file mode 100644 index 0000000000..24c1e761a4 --- /dev/null +++ b/bazel/pgp/BUILD @@ -0,0 +1,64 @@ +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") +load("@bazel_skylib//rules:common_settings.bzl", "string_flag") + +exports_files([ + "defs.bzl", + "toolchain.bzl", + "extensions.bzl", +]) + +# Ensures //pgp:extensions.bzl (not otherwise loaded - no `sq` platform is +# enabled by default) and the rest of the public/private starlark surface +# stay loadable and are covered by `bazel build //pgp/...`. +bzl_library( + name = "pgp_bzl", + srcs = [ + "defs.bzl", + "extensions.bzl", + "toolchain.bzl", + "//pgp/private:sign.bzl", + "//pgp/private:sq.bzl", + ], + visibility = ["//visibility:private"], + deps = [ + "//pgp/audit:audit_bzl", + "@bazel_skylib//rules:common_settings", + ], +) + +# Toolchain type for OpenPGP signer implementations. +# +# The default implementation wraps Sequoia PGP's `sq` (see extensions.bzl), +# but any binary implementing the signer CLI contract documented in +# toolchain.bzl can be registered instead. +toolchain_type( + name = "toolchain_type", + visibility = ["//visibility:public"], +) + +# Absolute host path of the passphrase-encrypted secret key. +# +# The key is a host path, not an artifact in the build graph: Bazel only ever +# sees the path, never the key file contents. The file is read by the signer at +# execution time. +# +# It must not live under the Bazel output tree or any artifact upload path. +string_flag( + name = "key_path", + build_setting_default = "", + visibility = ["//visibility:public"], +) + +# Absolute host path of the file containing the passphrase for the signing +# key. +# +# The passphrase is deliberately *not* part of the build graph: only this +# path is seen by Bazel, and only the path (never the passphrase) appears on +# the signer command line. The file is read by the signer at execution time. +# +# It must not live under the Bazel output tree or any artifact upload path. +string_flag( + name = "passphrase_path", + build_setting_default = "", + visibility = ["//visibility:public"], +) diff --git a/bazel/pgp/README.md b/bazel/pgp/README.md new file mode 100644 index 0000000000..02e119bb33 --- /dev/null +++ b/bazel/pgp/README.md @@ -0,0 +1,248 @@ +# OpenPGP signing (`//pgp`) + +Hermetic, secret-safe OpenPGP signing rules. + +Bazel has no notion of a secret: anything that is an action input is just +bytes that Bazel may hash, cache, upload to a CAS, or record in a build event +stream. These rules therefore make the safe configuration the *only* +configuration - the signing key must be passphrase-encrypted, the passphrase +is deliberately kept out of the build graph, and every signing action is +pinned to the local machine. + +## Security model + +### What these rules guarantee + +| Guarantee | How | +| --- | --- | +| **No key material ever enters the build graph** | The key is a host path, not an artifact; the signer additionally refuses unencrypted keys (`--require-encrypted-key`) so even the host file is ciphertext | +| Key content is part of the action key | `key_path` accepts `#sha256=`; the digest is in the action key and verified by the signer before use | +| Passphrase changes always take effect | The passphrase is never hashed (a digest would be an offline oracle for weak passphrases); instead signing actions are `no-cache` and therefore always re-run | +| The passphrase is never an action input, and is never hashed, cached or uploaded by Bazel | It is provided as an absolute host path via `--@envoy_toolshed//pgp:passphrase_path`; Bazel only ever sees the path | +| The passphrase never appears on a command line (`ps`, `--subcommands`, execution log) | Only `--passphrase-file ` is passed | +| The passphrase is never written to disk a second time | The signer reads it via process substitution (`--password-file <(...)`) rather than copying it to a temporary file | +| Signing actions never leave the machine | `no-remote`, `no-remote-exec`, `no-remote-cache`, `no-remote-cache-upload` and `no-cache` are hardcoded in the rule and are not user-overridable | +| Signing actions stay sandboxed | Unlike a `local`-tagged action, sandboxing is never disabled, so the signer cannot see anything on disk it was not explicitly given as an input | +| Signing actions are greppable in `aquery` | `mnemonic = "OpenPGPSign"` | +| No ambient environment reaches the signer | `use_default_shell_env = False` and an explicit, minimal `env = {"PATH": "/usr/bin:/bin"}`; the signer never consults `HOME`, `GNUPGHOME`, `SSH_AUTH_SOCK`, a gpg-agent socket, or any keyring/cert store on disk (`sq` is invoked with `--home none --cert-store none --key-store none --batch`) | +| The key is never copied into an output | The action writes only its declared output | +| A build without a configured passphrase or key fails loudly | The rule `fail()`s at analysis time | + +### What you still own + +| Concern | Why it is yours | +| --- | --- | +| The encrypted key file on the host | Put it somewhere dedicated - eg `${runner.temp}/gpg/signing-key.asc`, `chmod 600`, deleted when the job ends - and **never** under the Bazel output tree, `--disk_cache`, or any artifact upload path | +| Computing key digest | Compute the `#sha256=` fragment yourself (eg `sha256sum`) — the rules cannot | +| The passphrase file contents | Trailing newlines are stripped (matching `gpg --passphrase-file`); everything else is used verbatim | +| The plaintext passphrase file on the host | It must exist in plaintext during the build. Put it somewhere dedicated - eg `${runner.temp}/gpg/passphrase`, `chmod 600`, deleted when the job ends - and **never** under the Bazel output tree, `--disk_cache`, or any artifact upload path | +| `--sandbox_debug` | It leaves sandbox directories (including the action's inputs) on disk | +| Where the encrypted key comes from | The rules verify it is encrypted, not that it is *your* key | + +### Why not a label / why not `path_flag` + +Hermeticity is about action inputs; the key and passphrase are deliberately host capabilities (like `SSH_AUTH_SOCK`), invisible to remote executors because `no-remote-exec` guarantees they never see the action; a label or path-flag would pull content into the graph, which is exactly what we are avoiding. + +## Usage + +```starlark +load("@envoy_toolshed//pgp:defs.bzl", "pgp_sign_checksums", "pgp_sign_detached") + +pgp_sign_detached( + name = "signed_tarball", + src = ":tarball", +) + +pgp_sign_checksums( + name = "signed_checksums", + srcs = [":tarball", ":package"], +) +``` + +```console +$ bazel build //:signed_tarball \ + --@envoy_toolshed//pgp:key_path=/run/user/1000/gpg/signing-key.asc#sha256=... \ + --@envoy_toolshed//pgp:passphrase_path=/run/user/1000/gpg/passphrase +``` + +Without the flags the build fails at analysis time: + +``` +No key path configured for //:signed_tarball. +``` + +**CI wiring recommendation:** A setup step writes the encrypted key and passphrase to `${runner.temp}/gpg/`, `chmod 600`, computes the key digest, and passes both flags to bazel; no `~/.gnupg`, no agent, no `HOME` mount required. + +### Rules + +| Rule | Purpose | +| --- | --- | +| `pgp_sign(name, src, mode, out, armor)` | Core rule. Signs a single `src`. `mode` is one of `detached`, `cleartext`, `inline` | +| `pgp_sign_detached(name, src, out)` | Detached, armored signature (`.asc`) | +| `pgp_sign_cleartext(name, src, out)` | Cleartext signature - what `debsign` produces for `.changes`/`.dsc`, and what an apt `InRelease` is | +| `pgp_sign_checksums(name, srcs, algorithm, out)` | `shasum`-format checksums file for `srcs`, cleartext signed. Checksum generation is a separate, cacheable action - only signing handles secrets | +| `pgp_sign_changes_file(name, changes, out)` | Cleartext sign a Debian `.changes`/`.dsc` file itself. **Not** a full `debsign`: it does not sign referenced `.dsc`/`.buildinfo` files or rewrite their checksums - see the `TODO` on the rule | +| `pgp_toolchain(name, signer)` | Register a signer implementation for `//pgp:toolchain_type` | + +RPM header signing is **not** implemented here. + +> TODO(pgp): RPM header signing needs an OpenPGP implementation that can +> insert a signature into the RPM header rather than produce a standalone +> signature. It is intended to arrive via the toolchain swap path below (a +> purpose-built `sequoia-openpgp` + `rpm-rs` signer in `rust/`), without any +> change to these rules. + +## Toolchain + +`//pgp:toolchain_type` is implemented by any executable satisfying the signer +CLI contract: + +``` +signer --mode {detached|cleartext|inline} \ + --key \ + [--key-sha256 ] \ + --passphrase-file \ + --require-encrypted-key \ + --out \ + [--armor] \ + +``` + +The default implementation is a thin wrapper around Sequoia PGP's +[`sq`](https://sequoia-pgp.org) - a Rust OpenPGP implementation with no agent, +home directory or keyring state, used as the OpenPGP backend for `rpm` on +Fedora/RHEL and as `sqv` in apt >= 3.0. + +Upstream does not publish sha256-verifiable release binaries that could be +pinned here, so **no `sq` platform is fetched by default**. Enable the +platform(s) you need by supplying sha256s you have verified yourself: + +```starlark +pgp_ext = use_extension("@envoy_toolshed//pgp:extensions.bzl", "pgp_extension") +pgp_ext.setup( + sha256s = { + "linux_x86_64": "", + }, +) +use_repo(pgp_ext, "sq_linux_x86_64") + +register_toolchains("@sq_linux_x86_64//:toolchain") +``` + +`urls` can be used to point at your own audited mirror of the binary. + +The intended toolshed approach for this is to build and publish a pinned, +static `sq` in the `bins-v*` release, the same way `sysroot`/`llvm_minimal` +are, so `pgp_ext.setup()` can work with no consumer-supplied sha256 - that is +a follow-up, not part of this rule set. + +Swapping in a different signer (for example a purpose-built Rust signer) is a +matter of registering another toolchain - the rules do not change: + +```starlark +pgp_toolchain( + name = "my_signer_toolchain", + signer = "//my/signer", +) + +toolchain( + name = "my_toolchain", + toolchain = ":my_signer_toolchain", + toolchain_type = "@envoy_toolshed//pgp:toolchain_type", +) +``` + +## Auditing your own targets + +The audit is implemented as jq filters run by Starlark rules. The jq binary is +resolved from the hermetic `aspect_bazel_lib` jq toolchain; the audit never uses +host `jq` from `$PATH`. +The runnable `//pgp/audit:audit` likewise uses the toolchain jq via runfiles and +ignores any host `jq`. + +For captured `bazel aquery --output=jsonproto` output, use `pgp_audit` to emit +a JSON report and `pgp_audit_test` to fail when the report has failures: + +```starlark +load("@envoy_toolshed//pgp/audit:defs.bzl", "pgp_audit", "pgp_audit_test") + +pgp_audit( + name = "signing_audit_report", + aquery = ":captured.json", + forbidden_strings = ["known-forbidden-string"], +) + +pgp_audit_test( + name = "signing_audit_test", + aquery = ":captured.json", + forbidden_strings = ["known-forbidden-string"], +) +``` + +The report has the shape: + +```json +{"actions": 1, "failures": [{"check": 1, "target": "//pkg:target", "detail": "..."}]} +``` + +It asserts that: + +1. every `OpenPGPSign` action carries all of the required execution + requirements, +2. no input reachable from an `OpenPGPSign` action (resolved transitively via + `inputDepSetIds`) has a path matching + `(^|/)\.gnupg(/|$)|private-keys-v1\.d|passphrase|secret|\.(asc|pgp|gpg|key)$`, +3. no `OpenPGPSign` action has `HOME`, `GNUPGHOME` or `SSH_AUTH_SOCK` in its + environment, +4. no `OpenPGPSign` action passes a forbidden string (eg your passphrase) on + the command line, +5. every `OpenPGPSign` action has exactly one non-tool input artifact (the file being signed). + +For live use, either capture JSON yourself: + +```console +$ bazel aquery --output=jsonproto "deps(//distribution:signed)" > aquery.json +$ bazel run @envoy_toolshed//pgp/audit:audit -- \ + --forbid "$(cat /run/user/1000/gpg/passphrase)" \ + --aquery-json "$PWD/aquery.json" +``` + +or let the runnable audit target invoke `bazel aquery` first: + +```console +$ bazel run @envoy_toolshed//pgp/audit:audit -- \ + --forbid "$(cat /run/user/1000/gpg/passphrase)" \ + --@envoy_toolshed//pgp:key_path=/run/user/1000/gpg/signing-key.asc#sha256=... \ + --@envoy_toolshed//pgp:passphrase_path=/run/user/1000/gpg/passphrase \ + "deps(//distribution:signed)" +``` + +Any option other than `--forbid`/`--aquery-json` is passed through to +`bazel aquery`, so the targets can be audited in the configuration they are +actually built in. + +Use `deps(...)` to audit the whole universe reachable from a target rather +than only the actions the target itself owns. + +`//pgp/test:audit_test` runs the audit against captured `aquery` output +(`fixtures/audit.json`, the real output for the example targets in +`//pgp/test`) together with deliberately broken variants derived from it at +build time with the hermetic jq toolchain (a removed execution requirement, a +leaked environment variable, key material as an action input, a passphrase on +the command line), each of which the audit must reject. + +`//pgp/test:live_audit` (`bazel run //pgp/test:live_audit`) is the live +counterpart: it re-invokes `bazel aquery` against the real dependency graph +of the same example targets, rather than captured JSON, so a regression that +only shows up in the real graph is caught too. It cannot run as a sandboxed +`bazel test` since it shells out to `bazel`. + +## Alternative: signing after the build + +The most conservative option remains signing *outside* the build graph: +`bazel build` produces the unsigned artifacts and a separate `bazel run` +target signs them on the host. Nothing that happens in `bazel run` is an +action, so nothing is hashed, cached or uploaded. + +The toolchain here is deliberately reusable for that: the same signer binary +can be driven from a `bazel run` wrapper via the CLI contract above. diff --git a/bazel/pgp/audit/BUILD b/bazel/pgp/audit/BUILD new file mode 100644 index 0000000000..899cee43d2 --- /dev/null +++ b/bazel/pgp/audit/BUILD @@ -0,0 +1,24 @@ +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") +load(":defs.bzl", "pgp_audit_binary") + +exports_files([ + "audit.jq", + "audit.sh.tpl", + "audit_result_test.sh.tpl", + "defs.bzl", + "lib.jq", +]) + +pgp_audit_binary( + name = "audit", + visibility = ["//visibility:public"], +) + +bzl_library( + name = "audit_bzl", + srcs = ["defs.bzl"], + visibility = ["//pgp:__pkg__"], + deps = [ + "@bazel_skylib//lib:shell", + ], +) diff --git a/bazel/pgp/audit/audit.jq b/bazel/pgp/audit/audit.jq new file mode 100644 index 0000000000..d5ae60159f --- /dev/null +++ b/bazel/pgp/audit/audit.jq @@ -0,0 +1,48 @@ +include "lib"; + +(INDEX(.targets[]?; .id | tostring)) as $targets +| (INDEX(.pathFragments[]?; .id | tostring)) as $frags +| (INDEX(.depSetOfFiles[]?; .id | tostring)) as $depsets +| (INDEX(.artifacts[]?; .id | tostring)) as $arts +| (INDEX(.configuration[]?; .id | tostring)) as $configs +| signing_actions($mnemonic) as $actions +| tool_artifact_ids(.actions; $configs; $depsets) as $tool_ids +| def target($action): + (($targets[($action.targetId | tostring)] // {}).label // ($action.targetId // $action.mnemonic | tostring)); + def failure($check; $action; $detail): + {"check": $check, "target": target($action), "detail": $detail}; + { + "actions": ($actions | length), + "failures": ( + ([ + $actions[] as $action + | $required_exec_reqs[] as $req + | select(([$action.executionInfo[]?.key] | index($req) | not)) + | failure(1; $action; "missing execution requirement `" + $req + "`") + ] + [ + $actions[] as $action + | ($action | action_input_paths($depsets; $arts; $frags) + | map(select(test($forbidden_inputs_re; "i"))) + | unique) as $bad + | select($bad | length > 0) + | failure(2; $action; "input(s) look like key material or passphrases: " + ($bad | join(", "))) + ] + [ + $actions[] as $action + | $forbidden_env[] as $env + | select(([$action.environmentVariables[]?.key] | index($env)) != null) + | failure(3; $action; "forbidden environment variable `" + $env + "`") + ] + [ + $actions[] as $action + | $forbidden_strings[] as $forbidden + | select(($forbidden | length) > 0) + | select([$action.arguments[]? | select(contains($forbidden))] | length > 0) + | failure(4; $action; "forbidden string appears on command line") + ] + [ + $actions[] as $action + | ($action.arguments[-1]) as $expected_src + | ($action | non_tool_input_paths($depsets; $arts; $frags; $tool_ids) | unique) as $non_tool_inputs + | select($non_tool_inputs != [$expected_src]) + | failure(5; $action; "expected non-tool inputs [" + $expected_src + "], got [" + ($non_tool_inputs | join(", ")) + "]") + ]) + ) + } diff --git a/bazel/pgp/audit/audit.sh.tpl b/bazel/pgp/audit/audit.sh.tpl new file mode 100644 index 0000000000..e1954fda07 --- /dev/null +++ b/bazel/pgp/audit/audit.sh.tpl @@ -0,0 +1,90 @@ +#!/usr/bin/env bash +set -euo pipefail + +resolve_runfile() { + local path="$1" + if [[ -n "${RUNFILES_DIR:-}" && -e "${RUNFILES_DIR}/${path}" ]]; then + printf '%s\n' "${RUNFILES_DIR}/${path}" + return 0 + fi + if [[ -e "$0.runfiles/${path}" ]]; then + printf '%s\n' "$0.runfiles/${path}" + return 0 + fi + printf 'runfile not found: %s\n' "${path}" >&2 + return 1 +} + +jq_bin="$(resolve_runfile @JQ@)" +filter="$(resolve_runfile @FILTER@)" +lib_dir="$(resolve_runfile @LIB_DIR@)" +mnemonic=@MNEMONIC@ +required_exec_reqs=@REQUIRED_EXEC_REQS@ +forbidden_env=@FORBIDDEN_ENV@ +forbidden_inputs_re=@FORBIDDEN_INPUTS_RE@ +forbidden_strings=() +aquery_json= +bazel_opts=() +targets=() + +usage() { + cat >&2 <<'USAGE' +usage: audit [--forbid STRING]... [--aquery-json FILE] [BAZEL OPTION]... [TARGET...] + +With --aquery-json, audit captured `bazel aquery --output=jsonproto` JSON. +Without --aquery-json, run `bazel aquery` for the supplied target patterns first. +USAGE + exit 2 +} + +while [[ $# -gt 0 ]]; do + case "$1" in + --aquery-json) + [[ $# -ge 2 ]] || usage + aquery_json="$2" + shift 2 + ;; + --forbid) + [[ $# -ge 2 ]] || usage + forbidden_strings+=("$2") + shift 2 + ;; + -h|--help) + usage + ;; + -*) + bazel_opts+=("$1") + shift + ;; + *) + targets+=("$1") + shift + ;; + esac +done + +tmp="$(mktemp -d)" +trap 'rm -rf "$tmp"' EXIT + +if [[ -z "$aquery_json" ]]; then + [[ ${#targets[@]} -gt 0 ]] || usage + aquery_json="$tmp/aquery.json" + bazel aquery --output=jsonproto --include_artifacts=true \ + ${bazel_opts[@]+"${bazel_opts[@]}"} \ + "${targets[@]}" > "$aquery_json" +fi + +# shellcheck disable=SC2016 +forbidden_strings_json="$("$jq_bin" -n '$ARGS.positional' --args "${forbidden_strings[@]}")" +report="$tmp/report.json" +"$jq_bin" \ + -L "$lib_dir" \ + -f "$filter" \ + --arg mnemonic "$mnemonic" \ + --argjson required_exec_reqs "$required_exec_reqs" \ + --argjson forbidden_env "$forbidden_env" \ + --arg forbidden_inputs_re "$forbidden_inputs_re" \ + --argjson forbidden_strings "$forbidden_strings_json" \ + "$aquery_json" > "$report" +cat "$report" +"$jq_bin" -e '(.failures | length) == 0' "$report" > /dev/null diff --git a/bazel/pgp/audit/audit_result_test.sh.tpl b/bazel/pgp/audit/audit_result_test.sh.tpl new file mode 100644 index 0000000000..a5d07fc736 --- /dev/null +++ b/bazel/pgp/audit/audit_result_test.sh.tpl @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -euo pipefail + +resolve_runfile() { + local path="$1" + if [[ -n "${RUNFILES_DIR:-}" && -e "${RUNFILES_DIR}/${path}" ]]; then + printf '%s\n' "${RUNFILES_DIR}/${path}" + return 0 + fi + if [[ -e "$0.runfiles/${path}" ]]; then + printf '%s\n' "$0.runfiles/${path}" + return 0 + fi + printf 'runfile not found: %s\n' "${path}" >&2 + return 1 +} + +report="$(resolve_runfile @REPORT@)" +status="$(resolve_runfile @STATUS@)" +cat "$report" +exit "$(cat "$status")" diff --git a/bazel/pgp/audit/defs.bzl b/bazel/pgp/audit/defs.bzl new file mode 100644 index 0000000000..609fb1c8d6 --- /dev/null +++ b/bazel/pgp/audit/defs.bzl @@ -0,0 +1,178 @@ +"""Hermetic OpenPGP signing audit rules.""" + +load("@bazel_skylib//lib:shell.bzl", "shell") + +_JQ_TOOLCHAIN_TYPE = "@aspect_bazel_lib//lib:jq_toolchain_type" + +_DEFAULT_MNEMONIC = "OpenPGPSign" +_DEFAULT_REQUIRED_EXECUTION_REQUIREMENTS = [ + "no-cache", + "no-remote", + "no-remote-cache", + "no-remote-cache-upload", + "no-remote-exec", +] +_DEFAULT_FORBIDDEN_ENV = [ + "GNUPGHOME", + "HOME", + "SSH_AUTH_SOCK", +] +_DEFAULT_FORBIDDEN_INPUTS_REGEX = "(^|/)\\.gnupg(/|$)|private-keys-v1\\.d|passphrase|secret|\\.(asc|pgp|gpg|key)$" + +def _json_string_list(values): + return json.encode(values) + +def _runfiles_path(ctx, file): + path = file.short_path + if path.startswith("../"): + return path[3:] + return "%s/%s" % (ctx.workspace_name, path) + +def _jq_args(ctx, jq_bin): + args = ctx.actions.args() + args.add(jq_bin) + args.add("-L", ctx.file._lib.dirname) + args.add("-f", ctx.file._filter) + args.add_all(["--arg", "mnemonic", ctx.attr.mnemonic]) + args.add_all(["--argjson", "required_exec_reqs", _json_string_list(ctx.attr.required_execution_requirements)]) + args.add_all(["--argjson", "forbidden_env", _json_string_list(ctx.attr.forbidden_env)]) + args.add_all(["--arg", "forbidden_inputs_re", ctx.attr.forbidden_inputs_regex]) + args.add_all(["--argjson", "forbidden_strings", _json_string_list(ctx.attr.forbidden_strings)]) + args.add(ctx.file.aquery) + return args + +def _pgp_audit_impl(ctx): + out = ctx.actions.declare_file("%s.report.json" % ctx.label.name) + jq_bin = ctx.toolchains[_JQ_TOOLCHAIN_TYPE].jqinfo.bin + ctx.actions.run_shell( + command = "out=\"$1\"; shift; \"$@\" > \"$out\"", + arguments = [out.path, _jq_args(ctx, jq_bin)], + inputs = [ctx.file.aquery, ctx.file._filter, ctx.file._lib], + outputs = [out], + mnemonic = "OpenPGPAudit", + progress_message = "Auditing OpenPGP signing actions in %s" % ctx.file.aquery.short_path, + tools = [jq_bin], + ) + return [DefaultInfo(files = depset([out]))] + +pgp_audit = rule( + implementation = _pgp_audit_impl, + doc = "Run the OpenPGP signing audit over captured `bazel aquery --output=jsonproto` JSON.", + attrs = { + "aquery": attr.label( + doc = "Captured `bazel aquery --output=jsonproto` JSON.", + mandatory = True, + allow_single_file = [".json"], + ), + "forbidden_strings": attr.string_list( + doc = "Strings that must not appear in signing action argv.", + ), + "mnemonic": attr.string(default = _DEFAULT_MNEMONIC), + "required_execution_requirements": attr.string_list(default = _DEFAULT_REQUIRED_EXECUTION_REQUIREMENTS), + "forbidden_env": attr.string_list(default = _DEFAULT_FORBIDDEN_ENV), + "forbidden_inputs_regex": attr.string(default = _DEFAULT_FORBIDDEN_INPUTS_REGEX), + "_filter": attr.label(default = "//pgp/audit:audit.jq", allow_single_file = True), + "_lib": attr.label(default = "//pgp/audit:lib.jq", allow_single_file = True), + }, + toolchains = [_JQ_TOOLCHAIN_TYPE], +) + +def _pgp_audit_result_test_impl(ctx): + status = ctx.actions.declare_file("%s.exit_status" % ctx.label.name) + jq_bin = ctx.toolchains[_JQ_TOOLCHAIN_TYPE].jqinfo.bin + status_args = ctx.actions.args() + status_args.add(jq_bin) + status_args.add("-r") + status_args.add_all(["--argjson", "want_failures", "true" if ctx.attr.want_failures else "false"]) + status_args.add("if ((.failures | length) > 0) == $want_failures then \"0\" else \"1\" end") + status_args.add(ctx.file.report) + ctx.actions.run_shell( + command = "out=\"$1\"; shift; \"$@\" > \"$out\"", + arguments = [status.path, status_args], + inputs = [ctx.file.report], + outputs = [status], + mnemonic = "OpenPGPAuditAssert", + progress_message = "Checking OpenPGP audit result %s" % ctx.file.report.short_path, + tools = [jq_bin], + ) + + script = ctx.actions.declare_file("%s.sh" % ctx.label.name) + substitutions = { + "@REPORT@": shell.quote(_runfiles_path(ctx, ctx.file.report)), + "@STATUS@": shell.quote(_runfiles_path(ctx, status)), + } + ctx.actions.expand_template( + template = ctx.file._test_template, + output = script, + substitutions = substitutions, + is_executable = True, + ) + return [DefaultInfo( + executable = script, + runfiles = ctx.runfiles(files = [ctx.file.report, status]), + )] + +_pgp_audit_result_test = rule( + implementation = _pgp_audit_result_test_impl, + test = True, + attrs = { + "report": attr.label(mandatory = True, allow_single_file = [".json"]), + "want_failures": attr.bool(default = False), + "_test_template": attr.label(default = "//pgp/audit:audit_result_test.sh.tpl", allow_single_file = True), + }, + toolchains = [_JQ_TOOLCHAIN_TYPE], +) + +def pgp_audit_test(name, aquery, expect_failure = False, forbidden_strings = [], **kwargs): + """Audit captured aquery JSON and fail if the report has unexpected failures.""" + report_name = "%s_report" % name + pgp_audit( + name = report_name, + aquery = aquery, + forbidden_strings = forbidden_strings, + **kwargs + ) + _pgp_audit_result_test( + name = name, + report = ":%s" % report_name, + want_failures = expect_failure, + ) + +def _pgp_audit_binary_impl(ctx): + jq_bin = ctx.toolchains[_JQ_TOOLCHAIN_TYPE].jqinfo.bin + script = ctx.actions.declare_file("%s.sh" % ctx.label.name) + substitutions = { + "@JQ@": shell.quote(_runfiles_path(ctx, jq_bin)), + "@FILTER@": shell.quote(_runfiles_path(ctx, ctx.file._filter)), + "@LIB_DIR@": shell.quote(_runfiles_path(ctx, ctx.file._lib).rsplit("/", 1)[0]), + "@MNEMONIC@": shell.quote(ctx.attr.mnemonic), + "@REQUIRED_EXEC_REQS@": shell.quote(_json_string_list(ctx.attr.required_execution_requirements)), + "@FORBIDDEN_ENV@": shell.quote(_json_string_list(ctx.attr.forbidden_env)), + "@FORBIDDEN_INPUTS_RE@": shell.quote(ctx.attr.forbidden_inputs_regex), + } + ctx.actions.expand_template( + template = ctx.file._launcher_template, + output = script, + substitutions = substitutions, + is_executable = True, + ) + return [DefaultInfo( + executable = script, + runfiles = ctx.runfiles(files = [jq_bin, ctx.file._filter, ctx.file._lib]), + )] + +pgp_audit_binary = rule( + implementation = _pgp_audit_binary_impl, + doc = "Runnable OpenPGP audit CLI using jq from the hermetic toolchain.", + executable = True, + attrs = { + "mnemonic": attr.string(default = _DEFAULT_MNEMONIC), + "required_execution_requirements": attr.string_list(default = _DEFAULT_REQUIRED_EXECUTION_REQUIREMENTS), + "forbidden_env": attr.string_list(default = _DEFAULT_FORBIDDEN_ENV), + "forbidden_inputs_regex": attr.string(default = _DEFAULT_FORBIDDEN_INPUTS_REGEX), + "_filter": attr.label(default = "//pgp/audit:audit.jq", allow_single_file = True), + "_lib": attr.label(default = "//pgp/audit:lib.jq", allow_single_file = True), + "_launcher_template": attr.label(default = "//pgp/audit:audit.sh.tpl", allow_single_file = True), + }, + toolchains = [_JQ_TOOLCHAIN_TYPE], +) diff --git a/bazel/pgp/audit/lib.jq b/bazel/pgp/audit/lib.jq new file mode 100644 index 0000000000..a70a1b5413 --- /dev/null +++ b/bazel/pgp/audit/lib.jq @@ -0,0 +1,44 @@ +def frag_path($frags): + . as $id + | $frags[$id | tostring] as $f + | if ($f.parentId // null) != null then + ($f.parentId | frag_path($frags)) + "/" + $f.label + else + $f.label + end; + +def depset_artifact_ids($depsets): + . as $ids + | ($ids // []) + | map( + ($depsets[(. | tostring)] // {}) as $ds + | (($ds.directArtifactIds // []) + + (($ds.transitiveDepSetIds // []) | depset_artifact_ids($depsets))) + ) + | add // []; + +def signing_actions($mnemonic): + [.actions[]? | select(.mnemonic == $mnemonic)]; + +def action_input_ids($depsets): + (.inputDepSetIds // []) | depset_artifact_ids($depsets) | unique; + +def action_input_paths($depsets; $arts; $frags): + [action_input_ids($depsets)[] + | ($arts[(. | tostring)] // empty) as $art + | select($art.pathFragmentId != null) + | ($art.pathFragmentId | frag_path($frags))]; + +def tool_artifact_ids($actions; $configs; $depsets): + [$actions[]? + | select(($configs[(.configurationId | tostring)] // {} | .isTool // false) == true) + | ((.outputIds // [])[]?, (action_input_ids($depsets)[]?))] + | unique; + +def non_tool_input_paths($depsets; $arts; $frags; $tool_ids): + [action_input_ids($depsets)[] + | . as $id + | select(($tool_ids | index($id) | not)) + | ($arts[($id | tostring)] // empty) as $art + | select($art.pathFragmentId != null) + | ($art.pathFragmentId | frag_path($frags))]; diff --git a/bazel/pgp/defs.bzl b/bazel/pgp/defs.bzl new file mode 100644 index 0000000000..5597ad11d8 --- /dev/null +++ b/bazel/pgp/defs.bzl @@ -0,0 +1,138 @@ +"""Hermetic, secret-safe OpenPGP signing rules. + +See `//pgp:README.md` for the security model. + +Usage: + +```starlark +load("@envoy_toolshed//pgp:defs.bzl", "pgp_sign_detached") + +pgp_sign_detached( + name = "sign_tarball", + src = ":tarball", +) +``` + +```console +$ bazel build //:sign_tarball \\ + --@envoy_toolshed//pgp:key_path=/abs/path/to/key.asc \\ + --@envoy_toolshed//pgp:passphrase_path=/abs/path/to/passphrase +``` +""" + +load("//pgp/private:sign.bzl", _pgp_checksums = "pgp_checksums", _pgp_sign = "pgp_sign") +load("//pgp/private:sq.bzl", _sq_signer = "sq_signer") +load("//pgp:toolchain.bzl", _PgpSignerInfo = "PgpSignerInfo", _pgp_toolchain = "pgp_toolchain") + +PgpSignerInfo = _PgpSignerInfo +pgp_sign = _pgp_sign +pgp_checksums = _pgp_checksums +pgp_toolchain = _pgp_toolchain +sq_signer = _sq_signer + +def pgp_sign_detached(name, src, out = None, armor = True, **kwargs): + """Create a detached signature for `src`. + + Args: + name: Name of the target. + src: File to sign. + out: Output file, defaults to `.asc`. + armor: Emit ASCII armored output. + **kwargs: Additional arguments to the underlying rule. + """ + pgp_sign( + name = name, + src = src, + mode = "detached", + armor = armor, + out = out or "%s.asc" % _basename(src), + **kwargs + ) + +def pgp_sign_cleartext(name, src, out = None, **kwargs): + """Create a cleartext signed version of `src`. + + This is what `debsign` does to `.changes`/`.dsc` files, and what an apt + `InRelease` file is. + + Args: + name: Name of the target. + src: File to sign. + out: Output file, defaults to `.asc`. + **kwargs: Additional arguments to the underlying rule. + """ + pgp_sign( + name = name, + src = src, + mode = "cleartext", + out = out or "%s.asc" % _basename(src), + **kwargs + ) + +def pgp_sign_checksums( + name, + srcs, + algorithm = "sha256", + out = None, + checksums_out = None, + **kwargs): + """Generate a checksums file for `srcs` and cleartext sign it. + + Checksum generation is a separate, cacheable action - only the signing + step handles secrets. + + Args: + name: Name of the target. + srcs: Files to checksum. + algorithm: Checksum algorithm (`sha256` or `sha512`). + out: Output file, defaults to `checksums.txt.asc`. + checksums_out: Unsigned checksums file, defaults to `checksums.txt`. + **kwargs: Additional arguments to the underlying signing rule. + """ + checksums_out = checksums_out or "%s.checksums.txt" % name + pgp_checksums( + name = "%s_checksums" % name, + srcs = srcs, + algorithm = algorithm, + out = checksums_out, + tags = kwargs.get("tags"), + visibility = kwargs.get("visibility"), + ) + pgp_sign( + name = name, + src = "%s_checksums" % name, + mode = "cleartext", + out = out or "%s.asc" % checksums_out, + **kwargs + ) + +# TODO(pgp): this only clearsigns `changes` itself. Real `debsign` also signs +# the `.dsc`/`.buildinfo` files referenced by a `.changes` file and rewrites +# their sizes/hashes in the `Files:`/`Checksums-*` sections of the `.changes` +# before clearsigning it. Neither of those happen here - do not use this to +# produce a `.changes` file that itself references unsigned `.dsc`/ +# `.buildinfo` files that need re-signing. +def pgp_sign_changes_file(name, changes, out = None, **kwargs): + """Cleartext sign a single Debian `.changes` (or `.dsc`) file. + + This clearsigns `changes` itself - see the TODO above for what real + `debsign` additionally does that this does not. The signed file replaces + the original, so the output keeps the original basename (in a directory + named after the target). + + Args: + name: Name of the target. + changes: The `.changes`/`.dsc` file to clearsign. + out: Output file, defaults to `/`. + **kwargs: Additional arguments to the underlying rule. + """ + pgp_sign( + name = name, + src = changes, + mode = "cleartext", + out = out or "%s/%s" % (name, _basename(changes)), + **kwargs + ) + +def _basename(label): + return str(label).split(":")[-1].split("/")[-1] diff --git a/bazel/pgp/extensions.bzl b/bazel/pgp/extensions.bzl new file mode 100644 index 0000000000..1c99bd286a --- /dev/null +++ b/bazel/pgp/extensions.bzl @@ -0,0 +1,165 @@ +"""Module extension fetching the default OpenPGP signer binary (`sq`). + +Sequoia PGP's `sq` is a single, statically linkable Rust OpenPGP +implementation with no agent, home directory or keyring state to fight - the +same OpenPGP implementation used as the backend for `rpm` on Fedora/RHEL and +as `sqv` in apt >= 3.0. + +Upstream does not publish sha256-verifiable release binaries that could be +pinned here, so **no platform is fetched by default** - each platform must be +enabled by passing a sha256 you have verified yourself: + +```starlark +sq = use_extension("@envoy_toolshed//pgp:extensions.bzl", "pgp_extension") +sq.setup( + version = "1.4.0", + sha256s = { + "linux_x86_64": "", + }, +) +use_repo(sq, "sq_linux_x86_64") +register_toolchains("@sq_linux_x86_64//:toolchain") +``` + +`urls` can be used to point at your own (audited, mirrored) copy of the +binary. +""" + +# TODO(pgp): pin verified sha256s here once upstream publishes signed, +# reproducible release binaries. The URLs below are the upstream release +# artifact locations - they are unverified, so the corresponding platforms +# are disabled until a sha256 is supplied by the consumer. +SQ_VERSION = "1.4.0" + +SQ_PLATFORMS = { + "darwin_aarch64": struct( + # TODO(pgp): unverified, sha256 required to enable. + url = "https://gitlab.com/sequoia-pgp/sequoia-sq/-/releases/v{version}/downloads/sq-{version}-aarch64-apple-darwin", + exec_compatible_with = [ + "@platforms//os:macos", + "@platforms//cpu:aarch64", + ], + ), + "linux_aarch64": struct( + # TODO(pgp): unverified, sha256 required to enable. + url = "https://gitlab.com/sequoia-pgp/sequoia-sq/-/releases/v{version}/downloads/sq-{version}-aarch64-unknown-linux-musl", + exec_compatible_with = [ + "@platforms//os:linux", + "@platforms//cpu:aarch64", + ], + ), + "linux_x86_64": struct( + # TODO(pgp): unverified, sha256 required to enable. + url = "https://gitlab.com/sequoia-pgp/sequoia-sq/-/releases/v{version}/downloads/sq-{version}-x86_64-unknown-linux-musl", + exec_compatible_with = [ + "@platforms//os:linux", + "@platforms//cpu:x86_64", + ], + ), +} + +_BUILD_FILE = """ +load("@envoy_toolshed//pgp:defs.bzl", "pgp_toolchain", "sq_signer") + +package(default_visibility = ["//visibility:public"]) + +exports_files(["sq"]) + +sq_signer( + name = "signer", + sq = "sq", +) + +pgp_toolchain( + name = "signer_toolchain", + signer = ":signer", +) + +toolchain( + name = "toolchain", + exec_compatible_with = {exec_compatible_with}, + toolchain = ":signer_toolchain", + toolchain_type = "@envoy_toolshed//pgp:toolchain_type", +) +""" + +def _sq_repository_impl(ctx): + ctx.download( + url = ctx.attr.urls, + sha256 = ctx.attr.sha256, + output = "sq", + executable = True, + ) + ctx.file( + "BUILD", + _BUILD_FILE.format(exec_compatible_with = str(ctx.attr.exec_compatible_with)), + executable = False, + ) + +sq_repository = repository_rule( + implementation = _sq_repository_impl, + doc = "Downloads a `sq` binary and exposes it as an OpenPGP signer toolchain.", + attrs = { + "exec_compatible_with": attr.string_list( + doc = "Execution platform constraints for the toolchain.", + mandatory = True, + ), + "sha256": attr.string( + doc = "Verified sha256 of the `sq` binary.", + mandatory = True, + ), + "urls": attr.string_list( + doc = "URLs to download the `sq` binary from.", + mandatory = True, + ), + }, +) + +def _sq_repo(platform, version, url, sha256): + sq_repository( + name = "sq_%s" % platform, + urls = [url.format(version = version)], + sha256 = sha256, + exec_compatible_with = SQ_PLATFORMS[platform].exec_compatible_with, + ) + +def _pgp_extension_impl(module_ctx): + for mod in module_ctx.modules: + for tag in mod.tags.setup: + version = tag.version or SQ_VERSION + for platform, sha256 in tag.sha256s.items(): + if platform not in SQ_PLATFORMS: + fail("Unknown `sq` platform: %s (expected one of %s)" % ( + platform, + sorted(SQ_PLATFORMS), + )) + if not sha256: + fail("No sha256 given for `sq` platform: %s" % platform) + _sq_repo( + platform, + version, + tag.urls.get(platform) or SQ_PLATFORMS[platform].url, + sha256, + ) + +_setup = tag_class( + attrs = { + "sha256s": attr.string_dict( + doc = "Verified sha256 of the `sq` binary, keyed by platform.", + ), + "urls": attr.string_dict( + doc = "Override download URL, keyed by platform.", + ), + "version": attr.string( + doc = "`sq` version to fetch.", + default = SQ_VERSION, + ), + }, +) + +pgp_extension = module_extension( + implementation = _pgp_extension_impl, + tag_classes = { + "setup": _setup, + }, +) diff --git a/bazel/pgp/private/BUILD b/bazel/pgp/private/BUILD new file mode 100644 index 0000000000..dd3d4340cc --- /dev/null +++ b/bazel/pgp/private/BUILD @@ -0,0 +1,14 @@ +load("@rules_shell//shell:sh_binary.bzl", "sh_binary") + +exports_files([ + "checksums.sh", + "signer.sh", + "sign.bzl", + "sq.bzl", +]) + +sh_binary( + name = "checksums", + srcs = ["checksums.sh"], + visibility = ["//visibility:public"], +) diff --git a/bazel/pgp/private/checksums.sh b/bazel/pgp/private/checksums.sh new file mode 100755 index 0000000000..5d1f84c895 --- /dev/null +++ b/bazel/pgp/private/checksums.sh @@ -0,0 +1,51 @@ +#!/usr/bin/env bash +# +# Generate a `shasum`-format checksums file. +# +# checksums.sh ... +# +# Checksums are emitted with the basename of each input, matching the +# `sha256sum`/`shasum` output format used by the toolshed gpg actions. + +set -euo pipefail + +if [[ $# -lt 3 ]]; then + echo "usage: $0 ALGORITHM OUT INPUT..." >&2 + exit 2 +fi + +ALGORITHM="$1" +OUT="$2" +shift 2 + +case "$ALGORITHM" in + sha256|sha512) + ;; + *) + echo "unknown algorithm: ${ALGORITHM}" >&2 + exit 2 + ;; +esac + +BITS="${ALGORITHM#sha}" + +checksum () { + local file="$1" + if command -v "${ALGORITHM}sum" > /dev/null 2>&1; then + "${ALGORITHM}sum" "$file" + elif command -v shasum > /dev/null 2>&1; then + shasum -a "$BITS" "$file" + else + echo "no ${ALGORITHM} implementation found" >&2 + exit 1 + fi +} + +: > "$OUT" + +for input in "$@"; do + ( + cd "$(dirname "$input")" + checksum "$(basename "$input")" + ) >> "$OUT" +done diff --git a/bazel/pgp/private/sign.bzl b/bazel/pgp/private/sign.bzl new file mode 100644 index 0000000000..27fd04c3d7 --- /dev/null +++ b/bazel/pgp/private/sign.bzl @@ -0,0 +1,248 @@ +"""Implementation of the OpenPGP signing rules. + +Security model (see `//pgp:README.md`): + +- the secret key *must* be passphrase-encrypted, and the signer is always + invoked with `--require-encrypted-key` so it fails hard on unprotected + secret key packets. The only key material Bazel ever sees is ciphertext. +- the passphrase is deliberately not part of the build graph. It is provided + as an absolute host path via `--@envoy_toolshed//pgp:passphrase_path`, so + only the *path* is ever hashed, logged or cached. +- every signing action carries the full set of execution requirements below, + hardcoded here rather than left to the caller. +- no ambient environment is inherited (`use_default_shell_env = False`); only + an explicit, minimal `PATH` is set. +""" + +load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo") + +TOOLCHAIN_TYPE = "//pgp:toolchain_type" + +MODES = [ + "cleartext", + "detached", + "inline", +] + +# Hardcoded, not user-overridable: a signing action must never be shipped to, +# or cached in, anything other than the machine it runs on. The action stays +# sandboxed and local - `local` (no-sandbox) is deliberately not one of these. +EXECUTION_REQUIREMENTS = { + "no-cache": "1", + "no-remote": "1", + "no-remote-cache": "1", + "no-remote-cache-upload": "1", + "no-remote-exec": "1", +} + +# Minimal, explicit `PATH` for signing/checksums actions. `env = {}` alone +# only works because bash/glibc fall back to compiled-in default paths - +# setting `PATH` explicitly makes that dependency visible and pinned rather +# than implicit. +_ACTION_ENV = {"PATH": "/usr/bin:/bin"} + +MNEMONIC = "OpenPGPSign" + +_NO_PATH = """ +No {what} path configured for {label}. + +OpenPGP signing requires an absolute host path to the {what_desc}. +Pass the absolute path: + + bazel build {label} --@envoy_toolshed//pgp:{setting_flag}=/abs/path + +The file is read by the signer at execution time. Bazel never reads it, and it +must not live under the Bazel output tree or any artifact upload path. +""" + +_RELATIVE_PATH = """ +{what_cap} path for {label} is not absolute: {path} + +Bazel actions do not run in your working directory, so the {what} path must +be absolute. +""" + +_PASSPHRASE_FRAGMENT = """ +Passphrase path for {label} specifies a fragment: {path} + +Specifying a sha256 fragment on passphrase_path is forbidden: a passphrase digest is an oracle for weak passphrases. +""" + +_BAD_FRAGMENT = """ +Invalid sha256 fragment for {label}: {frag} + +Expected a fragment in the form #sha256=<64 lowercase hex characters>. +""" + +def _host_path(ctx, setting, what): + value = setting[BuildSettingInfo].value + what_cap = "Key" if what == "key" else "Passphrase" + what_desc = "passphrase-encrypted secret key" if what == "key" else "passphrase file" + setting_flag = "key_path" if what == "key" else "passphrase_path" + + if not value: + fail(_NO_PATH.format( + what = what, + what_desc = what_desc, + setting_flag = setting_flag, + label = ctx.label, + )) + + parts = value.split("#") + if len(parts) > 2: + fail("Invalid {what} path for {label}: contains multiple '#' characters".format( + what = what, + label = ctx.label, + )) + + path = parts[0] + if not path.startswith("/"): + fail(_RELATIVE_PATH.format( + what = what, + what_cap = what_cap, + label = ctx.label, + path = path, + )) + + sha256 = None + if len(parts) == 2: + frag = parts[1] + if what == "passphrase": + fail(_PASSPHRASE_FRAGMENT.format(label = ctx.label, path = value)) + + if not frag.startswith("sha256=") or len(frag) != 71: + fail(_BAD_FRAGMENT.format(label = ctx.label, frag = frag)) + + digest = frag[7:] + for c in digest.elems(): + if c not in "0123456789abcdef": + fail(_BAD_FRAGMENT.format(label = ctx.label, frag = frag)) + sha256 = digest + + return struct(path = path, sha256 = sha256) + +def _sign(ctx, mode, src, out, armor): + key_info = _host_path(ctx, ctx.attr._key_path, "key") + passphrase_info = _host_path(ctx, ctx.attr._passphrase_path, "passphrase") + signer = ctx.toolchains[TOOLCHAIN_TYPE].pgp_signer + args = ctx.actions.args() + args.add("--mode", mode) + args.add("--key", key_info.path) + if key_info.sha256: + args.add("--key-sha256", key_info.sha256) + + # Only the *path* is passed - never the passphrase itself, so it cannot + # show up in `ps`, `--subcommands` or an execution log. + args.add("--passphrase-file", passphrase_info.path) + args.add("--require-encrypted-key") + args.add("--out", out) + if armor: + args.add("--armor") + args.add(src) + ctx.actions.run( + executable = signer.signer, + arguments = [args], + inputs = [src], + outputs = [out], + tools = depset([signer.signer], transitive = [signer.runfiles.files]), + mnemonic = MNEMONIC, + progress_message = "Signing %s" % out.short_path, + execution_requirements = EXECUTION_REQUIREMENTS, + use_default_shell_env = False, + env = _ACTION_ENV, + ) + +def _pgp_sign_impl(ctx): + out = ctx.outputs.out + _sign( + ctx, + mode = ctx.attr.mode, + src = ctx.file.src, + out = out, + armor = ctx.attr.armor, + ) + return [DefaultInfo(files = depset([out]))] + +pgp_sign = rule( + implementation = _pgp_sign_impl, + doc = """Sign `src` with key specified via `--@envoy_toolshed//pgp:key_path`. + +The key must be a passphrase-encrypted OpenPGP secret key host path. The +passphrase host path is provided via `--@envoy_toolshed//pgp:passphrase_path`. +""", + attrs = { + "armor": attr.bool( + doc = "Emit ASCII armored output.", + default = True, + ), + "mode": attr.string( + doc = "Signature mode.", + default = "detached", + values = MODES, + ), + "out": attr.output( + doc = "Output file.", + mandatory = True, + ), + "src": attr.label( + doc = "The single file to sign.", + mandatory = True, + allow_single_file = True, + ), + "_key_path": attr.label( + default = "//pgp:key_path", + ), + "_passphrase_path": attr.label( + default = "//pgp:passphrase_path", + ), + }, + toolchains = [TOOLCHAIN_TYPE], +) + +def _pgp_checksums_impl(ctx): + out = ctx.outputs.out + args = ctx.actions.args() + args.add(ctx.attr.algorithm) + args.add(out) + args.add_all(ctx.files.srcs) + ctx.actions.run( + executable = ctx.executable._checksums, + arguments = [args], + inputs = ctx.files.srcs, + outputs = [out], + mnemonic = "OpenPGPChecksums", + progress_message = "Generating checksums %s" % out.short_path, + use_default_shell_env = False, + env = _ACTION_ENV, + ) + return [DefaultInfo(files = depset([out]))] + +pgp_checksums = rule( + implementation = _pgp_checksums_impl, + doc = """Generate a `shasum`-format checksums file for `srcs`. + +This action holds no secrets and is deliberately cacheable - only the +signing of the resulting file is a secret action. +""", + attrs = { + "algorithm": attr.string( + doc = "Checksum algorithm.", + default = "sha256", + values = ["sha256", "sha512"], + ), + "out": attr.output( + doc = "Output file.", + mandatory = True, + ), + "srcs": attr.label_list( + doc = "Files to checksum.", + mandatory = True, + allow_files = True, + ), + "_checksums": attr.label( + default = "//pgp/private:checksums", + executable = True, + cfg = "exec", + ), + }, +) diff --git a/bazel/pgp/private/signer.sh b/bazel/pgp/private/signer.sh new file mode 100755 index 0000000000..c1e2e70376 --- /dev/null +++ b/bazel/pgp/private/signer.sh @@ -0,0 +1,223 @@ +#!/usr/bin/env bash +# +# Thin wrapper translating the toolshed signer CLI contract to Sequoia PGP +# (`sq`) invocations. +# +# signer --mode {detached|cleartext|inline} \ +# --key \ +# [--key-sha256 ] \ +# --passphrase-file \ +# --require-encrypted-key \ +# --out \ +# [--armor] \ +# +# +# The wrapper deliberately never consults `HOME`, `GNUPGHOME`, a gpg-agent +# socket, or any on-disk keyring/cert store - `sq` is invoked with its own +# state directories disabled. It operates purely on the key file, the +# passphrase file and the declared inputs. + +set -euo pipefail + +# Baked in at build time by `sq_signer`. `SQ` can be set when running this +# script outside of Bazel (eg the integration test). +SQ="${SQ:-@SQ@}" + +MODE= +KEY= +KEY_SHA256= +PASSPHRASE_FILE= +OUT= +ARMOR=0 +REQUIRE_ENCRYPTED_KEY=0 +INPUTS=() + +usage () { + echo "usage: $0 --mode {detached|cleartext|inline} --key KEY" \ + "[--key-sha256 HEX] --passphrase-file PATH --out OUT [--armor]" \ + "[--require-encrypted-key] INPUT" >&2 + exit 2 +} + +while [[ $# -gt 0 ]]; do + case "$1" in + --mode) + MODE="$2" + shift 2 + ;; + --key) + KEY="$2" + shift 2 + ;; + --key-sha256) + KEY_SHA256="$2" + shift 2 + ;; + --passphrase-file) + PASSPHRASE_FILE="$2" + shift 2 + ;; + --out) + OUT="$2" + shift 2 + ;; + --armor) + ARMOR=1 + shift + ;; + --require-encrypted-key) + REQUIRE_ENCRYPTED_KEY=1 + shift + ;; + --) + shift + INPUTS+=("$@") + break + ;; + -*) + echo "unknown option: $1" >&2 + usage + ;; + *) + INPUTS+=("$1") + shift + ;; + esac +done + +if [[ -z "$MODE" || -z "$KEY" || -z "$PASSPHRASE_FILE" || -z "$OUT" ]]; then + usage +fi + +if [[ ${#INPUTS[@]} -eq 0 ]]; then + echo "no input files given" >&2 + usage +fi + +# The placeholder is split so that `sq_signer` template expansion does not +# rewrite this check too. +if [[ "$SQ" == "@""SQ""@" ]]; then + echo "no \`sq\` binary configured (SQ is unset and the wrapper was not" \ + "expanded by \`sq_signer\`)" >&2 + exit 1 +fi + +if [[ ${#INPUTS[@]} -gt 1 ]]; then + echo "the signer accepts a single input file, got ${#INPUTS[@]}" >&2 + exit 2 +fi + +if [[ "$KEY" != /* ]]; then + echo "key path must be absolute: $KEY (use --@envoy_toolshed//pgp:key_path)" >&2 + exit 1 +fi + +if [[ ! -f "$KEY" ]]; then + echo "key file not found: $KEY" >&2 + exit 1 +fi + +calc_sha256 () { + if command -v sha256sum > /dev/null 2>&1; then + sha256sum "$1" | awk '{print $1}' + elif command -v shasum > /dev/null 2>&1; then + shasum -a 256 "$1" | awk '{print $1}' + else + echo "neither sha256sum nor shasum found" >&2 + exit 1 + fi +} + +if [[ -n "$KEY_SHA256" ]]; then + actual_sha256="$(calc_sha256 "$KEY")" + if [[ "$actual_sha256" != "$KEY_SHA256" ]]; then + echo "key digest mismatch for $KEY: expected $KEY_SHA256, got $actual_sha256" >&2 + exit 1 + fi +fi + +# `sq` state directories are disabled unconditionally: no home, no cert store, +# no key store, and no prompting. Nothing outside the arguments is consulted. +sq () { + "$SQ" \ + --batch \ + --overwrite \ + --home none \ + --cert-store none \ + --key-store none \ + "$@" +} + +# Fail hard unless *every* secret key packet in the key file is protected. +# +# `sq inspect` prints `Secret key: Encrypted` or `Secret key: Unencrypted` for +# each secret key packet. A key with no secret key packets at all cannot sign, +# and is rejected here rather than producing a confusing error later. +require_encrypted_key () { + local inspected secret unencrypted + if ! inspected="$(sq inspect "$KEY" 2>&1)"; then + echo "unable to inspect key: $KEY" >&2 + echo "$inspected" >&2 + exit 1 + fi + secret="$(printf '%s\n' "$inspected" | grep -c 'Secret key: ' || true)" + unencrypted="$( + printf '%s\n' "$inspected" | grep -c 'Secret key: Unencrypted' || true)" + if [[ "$secret" -eq 0 ]]; then + echo "no secret key material found in ${KEY}" >&2 + exit 1 + fi + if [[ "$unencrypted" -ne 0 ]]; then + echo "REFUSING TO SIGN: ${KEY} contains unprotected secret key" \ + "material." >&2 + echo "The key given to the signing rules must be" \ + "passphrase-encrypted, so that the only key material Bazel can" \ + "hash, cache or upload is ciphertext." >&2 + exit 1 + fi +} + +if [[ "$REQUIRE_ENCRYPTED_KEY" -eq 1 ]]; then + require_encrypted_key +fi + +if [[ ! -f "$PASSPHRASE_FILE" ]]; then + echo "passphrase file not found: ${PASSPHRASE_FILE}" >&2 + echo "the passphrase file must exist on the host running the build," \ + "see --@envoy_toolshed//pgp:passphrase_path" >&2 + exit 1 +fi + +# `sq` uses the entire contents of the password file, including any trailing +# newline, whereas `gpg --passphrase-file` strips it. Normalize on the `gpg` +# behaviour without ever writing a second plaintext copy of the passphrase to +# disk: `sq` reads `--password-file` from an anonymous pipe created by +# process substitution (`/dev/fd/N` under bash), so the stripped passphrase +# exists only in memory/in-pipe, never as a file. +args=( + --password-file <(printf %s "$(cat "$PASSPHRASE_FILE")") + sign + --signer-file "$KEY") + +case "$MODE" in + detached) + args+=(--signature-file "$OUT") + ;; + cleartext) + args+=(--cleartext --output "$OUT") + ;; + inline) + args+=(--message --output "$OUT") + ;; + *) + echo "unknown mode: $MODE" >&2 + usage + ;; +esac + +# Cleartext signatures are armored by definition. +if [[ "$MODE" != "cleartext" && "$ARMOR" -eq 0 ]]; then + args+=(--binary) +fi + +sq "${args[@]}" "${INPUTS[0]}" diff --git a/bazel/pgp/private/sq.bzl b/bazel/pgp/private/sq.bzl new file mode 100644 index 0000000000..ba30f7ef64 --- /dev/null +++ b/bazel/pgp/private/sq.bzl @@ -0,0 +1,37 @@ +"""Rule wrapping a `sq` binary as a toolshed OpenPGP signer. + +The path of the `sq` binary is baked into the wrapper at analysis time so +that the signer does not need to resolve runfiles - signing actions run with +an empty environment. +""" + +def _sq_signer_impl(ctx): + out = ctx.actions.declare_file("%s.sh" % ctx.label.name) + ctx.actions.expand_template( + template = ctx.file._template, + output = out, + substitutions = {"@SQ@": ctx.file.sq.path}, + is_executable = True, + ) + return [DefaultInfo( + executable = out, + files = depset([out]), + runfiles = ctx.runfiles(files = [ctx.file.sq]), + )] + +sq_signer = rule( + implementation = _sq_signer_impl, + doc = "Wraps a `sq` binary as an implementation of the signer CLI contract.", + attrs = { + "sq": attr.label( + doc = "The `sq` binary.", + mandatory = True, + allow_single_file = True, + ), + "_template": attr.label( + default = "//pgp/private:signer.sh", + allow_single_file = True, + ), + }, + executable = True, +) diff --git a/bazel/pgp/test/BUILD b/bazel/pgp/test/BUILD new file mode 100644 index 0000000000..1acdf92ed9 --- /dev/null +++ b/bazel/pgp/test/BUILD @@ -0,0 +1,228 @@ +load("@aspect_bazel_lib//lib:jq.bzl", "jq") +load("@rules_shell//shell:sh_binary.bzl", "sh_binary") +load("@rules_shell//shell:sh_test.bzl", "sh_test") +load("//pgp/audit:defs.bzl", "pgp_audit_test") +load("//pgp:defs.bzl", "pgp_sign_changes_file", "pgp_sign_checksums", "pgp_sign_cleartext", "pgp_sign_detached", "pgp_toolchain") +load(":sign_test.bzl", "KEY_FRAGMENT_DIGEST", "args_test", "args_with_fragment_test", "bad_key_fragment_test", "env_test", "execution_requirements_test", "inputs_test", "no_key_test", "no_passphrase_test", "passphrase_fragment_test", "relative_key_test", "relative_passphrase_test") + +# Stub signer/toolchain for the analysis tests. Real signing requires a +# registered `sq` toolchain, see //pgp:extensions.bzl. +sh_binary( + name = "stub_signer", + srcs = ["stub_signer.sh"], +) + +pgp_toolchain( + name = "stub_signer_toolchain", + signer = ":stub_signer", +) + +toolchain( + name = "stub_toolchain", + toolchain = ":stub_signer_toolchain", + toolchain_type = "//pgp:toolchain_type", +) + +# Example signing targets. They are `manual` because building them requires +# `--@envoy_toolshed//pgp:key_path`, `--@envoy_toolshed//pgp:passphrase_path` +# and a real signer toolchain. +pgp_sign_detached( + name = "example_detached", + src = "fixtures/example.txt", + tags = ["manual"], +) + +pgp_sign_cleartext( + name = "example_cleartext", + src = "fixtures/example.txt", + out = "example.txt.cleartext.asc", + tags = ["manual"], +) + +pgp_sign_checksums( + name = "example_checksums", + srcs = [ + "fixtures/example.changes", + "fixtures/example.txt", + ], + tags = ["manual"], +) + +pgp_sign_changes_file( + name = "example_deb_changes", + changes = "fixtures/example.changes", + tags = ["manual"], +) + +execution_requirements_test( + name = "execution_requirements_test", +) + +env_test( + name = "env_test", + target_under_test = ":example_detached", +) + +args_test( + name = "detached_args_test", + mode = "detached", + target_under_test = ":example_detached", +) + +args_with_fragment_test( + name = "detached_args_with_fragment_test", + expect_key_sha256 = KEY_FRAGMENT_DIGEST, + mode = "detached", + target_under_test = ":example_detached", +) + +args_test( + name = "cleartext_args_test", + mode = "cleartext", + target_under_test = ":example_cleartext", +) + +args_test( + name = "checksums_args_test", + mode = "cleartext", + target_under_test = ":example_checksums", +) + +args_test( + name = "deb_changes_args_test", + mode = "cleartext", + target_under_test = ":example_deb_changes", +) + +inputs_test( + name = "inputs_test", + src = "fixtures/example.txt", + target_under_test = ":example_detached", +) + +no_key_test( + name = "no_key_test", + target_under_test = ":example_detached", +) + +relative_key_test( + name = "relative_key_test", + target_under_test = ":example_detached", +) + +bad_key_fragment_test( + name = "bad_key_fragment_test", + target_under_test = ":example_detached", +) + +no_passphrase_test( + name = "no_passphrase_test", + target_under_test = ":example_detached", +) + +relative_passphrase_test( + name = "relative_passphrase_test", + target_under_test = ":example_detached", +) + +passphrase_fragment_test( + name = "passphrase_fragment_test", + target_under_test = ":example_detached", +) + +PASSPHRASE = "correct-horse-battery-staple" + +pgp_audit_test( + name = "audit_test", + aquery = "fixtures/audit.json", +) + +jq( + name = "audit_missing_exec_req", + srcs = ["fixtures/audit.json"], + filter_file = "fixtures/breakers/missing-exec-req.jq", + out = "audit_missing_exec_req.json", +) + +jq( + name = "audit_env_leak", + srcs = ["fixtures/audit.json"], + filter_file = "fixtures/breakers/env-leak.jq", + out = "audit_env_leak.json", +) + +jq( + name = "audit_passphrase_argv", + srcs = ["fixtures/audit.json"], + filter_file = "fixtures/breakers/passphrase-argv.jq", + args = [ + "--arg", + "passphrase", + PASSPHRASE, + ], + out = "audit_passphrase_argv.json", +) + +jq( + name = "audit_key_material_input", + srcs = ["fixtures/audit.json"], + filter_file = "fixtures/breakers/key-material-input.jq", + out = "audit_key_material_input.json", +) + +jq( + name = "audit_key_artifact_input", + srcs = ["fixtures/audit.json"], + filter_file = "fixtures/breakers/key-artifact-input.jq", + out = "audit_key_artifact_input.json", +) + +pgp_audit_test( + name = "audit_missing_exec_req_test", + aquery = ":audit_missing_exec_req", + expect_failure = True, +) + +pgp_audit_test( + name = "audit_env_leak_test", + aquery = ":audit_env_leak", + expect_failure = True, +) + +pgp_audit_test( + name = "audit_passphrase_argv_test", + aquery = ":audit_passphrase_argv", + expect_failure = True, + forbidden_strings = [PASSPHRASE], +) + +pgp_audit_test( + name = "audit_key_material_input_test", + aquery = ":audit_key_material_input", + expect_failure = True, +) + +pgp_audit_test( + name = "audit_key_artifact_input_test", + aquery = ":audit_key_artifact_input", + expect_failure = True, +) + +# Runs the audit against a real `bazel aquery` of this package's example +# targets, rather than captured JSON (see `//pgp/test:audit_test` for that). +# `manual`: it shells out to `bazel`, so it cannot run as a sandboxed test - +# invoke explicitly with `bazel run //pgp/test:live_audit`, including in CI. +sh_binary( + name = "live_audit", + srcs = ["live_audit.sh"], + tags = ["manual"], +) + +# Signs with a real `sq`, if one is available (`SQ` or `$PATH`), and asserts +# that unencrypted keys are rejected. Skipped when `sq` is not installed. +sh_test( + name = "signer_test", + size = "medium", + srcs = ["signer_test.sh"], + data = ["//pgp/private:signer.sh"], +) diff --git a/bazel/pgp/test/fixtures/audit.json b/bazel/pgp/test/fixtures/audit.json new file mode 100644 index 0000000000..ee1ab22c23 --- /dev/null +++ b/bazel/pgp/test/fixtures/audit.json @@ -0,0 +1,556 @@ +{ + "artifacts": [{ + "id": 1, + "pathFragmentId": 1 + }, { + "id": 2, + "pathFragmentId": 7 + }, { + "id": 3, + "pathFragmentId": 10 + }, { + "id": 4, + "pathFragmentId": 12 + }, { + "id": 5, + "pathFragmentId": 17 + }, { + "id": 6, + "pathFragmentId": 18 + }, { + "id": 7, + "pathFragmentId": 19 + }, { + "id": 8, + "pathFragmentId": 21 + }, { + "id": 9, + "pathFragmentId": 24 + }, { + "id": 10, + "pathFragmentId": 25 + }, { + "id": 11, + "pathFragmentId": 26 + }, { + "id": 12, + "pathFragmentId": 27 + }, { + "id": 13, + "pathFragmentId": 28 + }, { + "id": 14, + "pathFragmentId": 30 + }, { + "id": 15, + "pathFragmentId": 32 + }, { + "id": 16, + "pathFragmentId": 33 + }, { + "id": 17, + "pathFragmentId": 34 + }, { + "id": 18, + "pathFragmentId": 35 + }, { + "id": 19, + "pathFragmentId": 37 + }], + "actions": [{ + "targetId": 1, + "actionKey": "2468ab54784a3380723c3780c81dd71995006585e8d4711e58b18ca494c11613", + "mnemonic": "OpenPGPSign", + "configurationId": 1, + "arguments": ["bazel-out/k8-opt-exec-ST-d57f47055a04/bin/pgp/test/stub_signer", "--mode", "detached", "--key", "/tmp/nonexistent-key", "--key-sha256", "0000000000000000000000000000000000000000000000000000000000000000", "--passphrase-file", "/tmp/nonexistent", "--require-encrypted-key", "--out", "bazel-out/k8-fastbuild/bin/pgp/test/example.txt.asc", "--armor", "pgp/test/fixtures/example.txt"], + "environmentVariables": [{ + "key": "PATH", + "value": "/usr/bin:/bin" + }], + "inputDepSetIds": [1], + "outputIds": [4], + "executionInfo": [{ + "key": "no-cache", + "value": "1" + }, { + "key": "no-remote", + "value": "1" + }, { + "key": "no-remote-cache", + "value": "1" + }, { + "key": "no-remote-cache-upload", + "value": "1" + }, { + "key": "no-remote-exec", + "value": "1" + }], + "primaryOutputId": 4, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 2, + "actionKey": "7a39b61d5744a8903119e17b3ddc7e56e330f240d2bead98c3ba081a81b5c9ac", + "mnemonic": "ExecutableSymlink", + "configurationId": 2, + "inputDepSetIds": [3], + "outputIds": [1], + "primaryOutputId": 1, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 2, + "actionKey": "eaf13d83a5a688fa5b315b94d7c186b51fe8ddc267c803905bf1de21a82abbc4", + "mnemonic": "RepoMappingManifest", + "configurationId": 2, + "outputIds": [5], + "primaryOutputId": 5, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 2, + "actionKey": "7d46f811cc2a7b79fb8853e495b8a1218ac20c0f2cf80486de9a8281b87d0759", + "mnemonic": "SourceSymlinkManifest", + "configurationId": 2, + "outputIds": [6], + "primaryOutputId": 6, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 2, + "actionKey": "9c20914ea2c513df3992398d5792327fdad2ae7934a575ae8998294bde3f5b5c", + "mnemonic": "SymlinkTree", + "configurationId": 2, + "inputDepSetIds": [4], + "outputIds": [7], + "primaryOutputId": 7, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 2, + "actionKey": "709e80c88487a2411e1ee4dfb9f22a861492d20c4765150c0c794abd70f8147c", + "mnemonic": "Middleman", + "configurationId": 2, + "inputDepSetIds": [5], + "outputIds": [8], + "primaryOutputId": 8, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 3, + "actionKey": "795631eb42ec0f2d1fca807e9cdacf333b7c7328fbe6e3794edd71df80763bb2", + "mnemonic": "OpenPGPSign", + "configurationId": 1, + "arguments": ["bazel-out/k8-opt-exec-ST-d57f47055a04/bin/pgp/test/stub_signer", "--mode", "cleartext", "--key", "/tmp/nonexistent-key", "--key-sha256", "0000000000000000000000000000000000000000000000000000000000000000", "--passphrase-file", "/tmp/nonexistent", "--require-encrypted-key", "--out", "bazel-out/k8-fastbuild/bin/pgp/test/example.txt.cleartext.asc", "--armor", "pgp/test/fixtures/example.txt"], + "environmentVariables": [{ + "key": "PATH", + "value": "/usr/bin:/bin" + }], + "inputDepSetIds": [8], + "outputIds": [9], + "executionInfo": [{ + "key": "no-cache", + "value": "1" + }, { + "key": "no-remote", + "value": "1" + }, { + "key": "no-remote-cache", + "value": "1" + }, { + "key": "no-remote-cache-upload", + "value": "1" + }, { + "key": "no-remote-exec", + "value": "1" + }], + "primaryOutputId": 9, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 4, + "actionKey": "8b8557eadd8da99d1d89aaa0db840d3b32709ac2e4dd61d9f6f27cfb1d736d32", + "mnemonic": "OpenPGPSign", + "configurationId": 1, + "arguments": ["bazel-out/k8-opt-exec-ST-d57f47055a04/bin/pgp/test/stub_signer", "--mode", "cleartext", "--key", "/tmp/nonexistent-key", "--key-sha256", "0000000000000000000000000000000000000000000000000000000000000000", "--passphrase-file", "/tmp/nonexistent", "--require-encrypted-key", "--out", "bazel-out/k8-fastbuild/bin/pgp/test/example_checksums.checksums.txt.asc", "--armor", "bazel-out/k8-fastbuild/bin/pgp/test/example_checksums.checksums.txt"], + "environmentVariables": [{ + "key": "PATH", + "value": "/usr/bin:/bin" + }], + "inputDepSetIds": [10], + "outputIds": [11], + "executionInfo": [{ + "key": "no-cache", + "value": "1" + }, { + "key": "no-remote", + "value": "1" + }, { + "key": "no-remote-cache", + "value": "1" + }, { + "key": "no-remote-cache-upload", + "value": "1" + }, { + "key": "no-remote-exec", + "value": "1" + }], + "primaryOutputId": 11, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 5, + "actionKey": "2a271376d24e8b8a039d2b2b64548240cf160c46dc5881fdcaf829c5adf5101c", + "mnemonic": "OpenPGPChecksums", + "configurationId": 1, + "arguments": ["bazel-out/k8-opt-exec-ST-d57f47055a04/bin/pgp/private/checksums", "sha256", "bazel-out/k8-fastbuild/bin/pgp/test/example_checksums.checksums.txt", "pgp/test/fixtures/example.changes", "pgp/test/fixtures/example.txt"], + "environmentVariables": [{ + "key": "PATH", + "value": "/usr/bin:/bin" + }], + "inputDepSetIds": [12], + "outputIds": [10], + "primaryOutputId": 10, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 6, + "actionKey": "7a39b61d5744a8903119e17b3ddc7e56e330f240d2bead98c3ba081a81b5c9ac", + "mnemonic": "ExecutableSymlink", + "configurationId": 2, + "inputDepSetIds": [16], + "outputIds": [14], + "primaryOutputId": 14, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 6, + "actionKey": "eaf13d83a5a688fa5b315b94d7c186b51fe8ddc267c803905bf1de21a82abbc4", + "mnemonic": "RepoMappingManifest", + "configurationId": 2, + "outputIds": [16], + "primaryOutputId": 16, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 6, + "actionKey": "fb28a1a086c02d9bd606f77abe0fad0d248758c2050cf4b5409a3f302a1608d6", + "mnemonic": "SourceSymlinkManifest", + "configurationId": 2, + "outputIds": [17], + "primaryOutputId": 17, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 6, + "actionKey": "47bcad3fab0dc6d93e8a4cf2069b37456f8bedd7b8304f1fb315ae423c557ee1", + "mnemonic": "SymlinkTree", + "configurationId": 2, + "inputDepSetIds": [17], + "outputIds": [18], + "primaryOutputId": 18, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 6, + "actionKey": "709e80c88487a2411e1ee4dfb9f22a861492d20c4765150c0c794abd70f8147c", + "mnemonic": "Middleman", + "configurationId": 2, + "inputDepSetIds": [18], + "outputIds": [15], + "primaryOutputId": 15, + "executionPlatform": "@@platforms//host:host" + }, { + "targetId": 7, + "actionKey": "460abfc5256a43bbe04fff6f7ea4846c3deeede48c175d07fb3117ac9e70e70b", + "mnemonic": "OpenPGPSign", + "configurationId": 1, + "arguments": ["bazel-out/k8-opt-exec-ST-d57f47055a04/bin/pgp/test/stub_signer", "--mode", "cleartext", "--key", "/tmp/nonexistent-key", "--key-sha256", "0000000000000000000000000000000000000000000000000000000000000000", "--passphrase-file", "/tmp/nonexistent", "--require-encrypted-key", "--out", "bazel-out/k8-fastbuild/bin/pgp/test/example_deb_changes/example.changes", "--armor", "pgp/test/fixtures/example.changes"], + "environmentVariables": [{ + "key": "PATH", + "value": "/usr/bin:/bin" + }], + "inputDepSetIds": [20], + "outputIds": [19], + "executionInfo": [{ + "key": "no-cache", + "value": "1" + }, { + "key": "no-remote", + "value": "1" + }, { + "key": "no-remote-cache", + "value": "1" + }, { + "key": "no-remote-cache-upload", + "value": "1" + }, { + "key": "no-remote-exec", + "value": "1" + }], + "primaryOutputId": 19, + "executionPlatform": "@@platforms//host:host" + }], + "targets": [{ + "id": 1, + "label": "//pgp/test:example_detached", + "ruleClassId": 1 + }, { + "id": 2, + "label": "//pgp/test:stub_signer", + "ruleClassId": 2 + }, { + "id": 3, + "label": "//pgp/test:example_cleartext", + "ruleClassId": 1 + }, { + "id": 4, + "label": "//pgp/test:example_checksums", + "ruleClassId": 1 + }, { + "id": 5, + "label": "//pgp/test:example_checksums_checksums", + "ruleClassId": 3 + }, { + "id": 6, + "label": "//pgp/private:checksums", + "ruleClassId": 2 + }, { + "id": 7, + "label": "//pgp/test:example_deb_changes", + "ruleClassId": 1 + }], + "depSetOfFiles": [{ + "id": 2, + "directArtifactIds": [1, 2] + }, { + "id": 1, + "transitiveDepSetIds": [2], + "directArtifactIds": [3] + }, { + "id": 3, + "directArtifactIds": [2] + }, { + "id": 4, + "directArtifactIds": [6] + }, { + "id": 7, + "directArtifactIds": [2, 1] + }, { + "id": 6, + "transitiveDepSetIds": [7], + "directArtifactIds": [1] + }, { + "id": 5, + "transitiveDepSetIds": [6], + "directArtifactIds": [7, 5] + }, { + "id": 9, + "directArtifactIds": [1, 2] + }, { + "id": 8, + "transitiveDepSetIds": [9], + "directArtifactIds": [3] + }, { + "id": 11, + "directArtifactIds": [1, 2] + }, { + "id": 10, + "transitiveDepSetIds": [11], + "directArtifactIds": [10] + }, { + "id": 13, + "directArtifactIds": [12, 3] + }, { + "id": 15, + "directArtifactIds": [13, 14] + }, { + "id": 14, + "transitiveDepSetIds": [15], + "directArtifactIds": [15, 14] + }, { + "id": 12, + "transitiveDepSetIds": [13, 14] + }, { + "id": 16, + "directArtifactIds": [13] + }, { + "id": 17, + "directArtifactIds": [17] + }, { + "id": 19, + "transitiveDepSetIds": [15], + "directArtifactIds": [14] + }, { + "id": 18, + "transitiveDepSetIds": [19], + "directArtifactIds": [18, 16] + }, { + "id": 21, + "directArtifactIds": [1, 2] + }, { + "id": 20, + "transitiveDepSetIds": [21], + "directArtifactIds": [12] + }], + "configuration": [{ + "id": 1, + "mnemonic": "k8-fastbuild", + "platformName": "k8", + "checksum": "8ccb9e558e20c7159868e719a2666da8cd26251838da34ccc0e31e6bd46133ed" + }, { + "id": 2, + "mnemonic": "k8-opt-exec-ST-d57f47055a04", + "platformName": "k8", + "checksum": "34af391bb0ee1e2ba258cc21b67b093d0e298f56dd6cde7ba6d109a72017ecd1", + "isTool": true + }], + "ruleClasses": [{ + "id": 1, + "name": "pgp_sign" + }, { + "id": 2, + "name": "sh_binary" + }, { + "id": 3, + "name": "pgp_checksums" + }], + "pathFragments": [{ + "id": 6, + "label": "bazel-out" + }, { + "id": 5, + "label": "k8-opt-exec-ST-d57f47055a04", + "parentId": 6 + }, { + "id": 4, + "label": "bin", + "parentId": 5 + }, { + "id": 3, + "label": "pgp", + "parentId": 4 + }, { + "id": 2, + "label": "test", + "parentId": 3 + }, { + "id": 1, + "label": "stub_signer", + "parentId": 2 + }, { + "id": 9, + "label": "pgp" + }, { + "id": 8, + "label": "test", + "parentId": 9 + }, { + "id": 7, + "label": "stub_signer.sh", + "parentId": 8 + }, { + "id": 11, + "label": "fixtures", + "parentId": 8 + }, { + "id": 10, + "label": "example.txt", + "parentId": 11 + }, { + "id": 16, + "label": "k8-fastbuild", + "parentId": 6 + }, { + "id": 15, + "label": "bin", + "parentId": 16 + }, { + "id": 14, + "label": "pgp", + "parentId": 15 + }, { + "id": 13, + "label": "test", + "parentId": 14 + }, { + "id": 12, + "label": "example.txt.asc", + "parentId": 13 + }, { + "id": 17, + "label": "stub_signer.repo_mapping", + "parentId": 2 + }, { + "id": 18, + "label": "stub_signer.runfiles_manifest", + "parentId": 2 + }, { + "id": 20, + "label": "stub_signer.runfiles", + "parentId": 2 + }, { + "id": 19, + "label": "MANIFEST", + "parentId": 20 + }, { + "id": 23, + "label": "internal", + "parentId": 5 + }, { + "id": 22, + "label": "_middlemen", + "parentId": 23 + }, { + "id": 21, + "label": "pgp_Stest_Sstub_Usigner-runfiles", + "parentId": 22 + }, { + "id": 24, + "label": "example.txt.cleartext.asc", + "parentId": 13 + }, { + "id": 25, + "label": "example_checksums.checksums.txt", + "parentId": 13 + }, { + "id": 26, + "label": "example_checksums.checksums.txt.asc", + "parentId": 13 + }, { + "id": 27, + "label": "example.changes", + "parentId": 11 + }, { + "id": 29, + "label": "private", + "parentId": 9 + }, { + "id": 28, + "label": "checksums.sh", + "parentId": 29 + }, { + "id": 31, + "label": "private", + "parentId": 3 + }, { + "id": 30, + "label": "checksums", + "parentId": 31 + }, { + "id": 32, + "label": "pgp_Sprivate_Schecksums-runfiles", + "parentId": 22 + }, { + "id": 33, + "label": "checksums.repo_mapping", + "parentId": 31 + }, { + "id": 34, + "label": "checksums.runfiles_manifest", + "parentId": 31 + }, { + "id": 36, + "label": "checksums.runfiles", + "parentId": 31 + }, { + "id": 35, + "label": "MANIFEST", + "parentId": 36 + }, { + "id": 38, + "label": "example_deb_changes", + "parentId": 13 + }, { + "id": 37, + "label": "example.changes", + "parentId": 38 + }] +} diff --git a/bazel/pgp/test/fixtures/breakers/env-leak.jq b/bazel/pgp/test/fixtures/breakers/env-leak.jq new file mode 100644 index 0000000000..5fc1fc3552 --- /dev/null +++ b/bazel/pgp/test/fixtures/breakers/env-leak.jq @@ -0,0 +1,4 @@ +.actions |= map( + if .mnemonic == "OpenPGPSign" then + .environmentVariables = ((.environmentVariables // []) + [{"key": "HOME", "value": "/x"}]) + else . end) diff --git a/bazel/pgp/test/fixtures/breakers/key-artifact-input.jq b/bazel/pgp/test/fixtures/breakers/key-artifact-input.jq new file mode 100644 index 0000000000..b9ff5dfb09 --- /dev/null +++ b/bazel/pgp/test/fixtures/breakers/key-artifact-input.jq @@ -0,0 +1,13 @@ +([.pathFragments[].id] | max) as $f0 +| ([.artifacts[].id] | max) as $a0 +| ([.depSetOfFiles[].id] | max) as $d0 +| ($f0 + 1) as $f1 +| ($a0 + 1) as $art +| ($d0 + 1) as $ds +| .pathFragments += [ + {"id": $f1, "label": "signing-key.asc"} + ] +| .artifacts += [{"id": $art, "pathFragmentId": $f1}] +| .depSetOfFiles += [{"id": $ds, "directArtifactIds": [$art]}] +| (.actions | map(.mnemonic == "OpenPGPSign") | index(true)) as $idx +| .actions[$idx].inputDepSetIds += [$ds] diff --git a/bazel/pgp/test/fixtures/breakers/key-material-input.jq b/bazel/pgp/test/fixtures/breakers/key-material-input.jq new file mode 100644 index 0000000000..7c37512e7a --- /dev/null +++ b/bazel/pgp/test/fixtures/breakers/key-material-input.jq @@ -0,0 +1,17 @@ +([.pathFragments[].id] | max) as $f0 +| ([.artifacts[].id] | max) as $a0 +| ([.depSetOfFiles[].id] | max) as $d0 +| ($f0 + 1) as $f1 +| ($f0 + 2) as $f2 +| ($f0 + 3) as $f3 +| ($a0 + 1) as $art +| ($d0 + 1) as $ds +| .pathFragments += [ + {"id": $f1, "label": ".gnupg"}, + {"id": $f2, "label": "private-keys-v1.d", "parentId": $f1}, + {"id": $f3, "label": "DEADBEEF.key", "parentId": $f2} + ] +| .artifacts += [{"id": $art, "pathFragmentId": $f3}] +| .depSetOfFiles += [{"id": $ds, "directArtifactIds": [$art]}] +| (.actions | map(.mnemonic == "OpenPGPSign") | index(true)) as $idx +| .actions[$idx].inputDepSetIds += [$ds] diff --git a/bazel/pgp/test/fixtures/breakers/missing-exec-req.jq b/bazel/pgp/test/fixtures/breakers/missing-exec-req.jq new file mode 100644 index 0000000000..6ac2952471 --- /dev/null +++ b/bazel/pgp/test/fixtures/breakers/missing-exec-req.jq @@ -0,0 +1,4 @@ +.actions |= map( + if .mnemonic == "OpenPGPSign" then + .executionInfo |= map(select(.key != "no-cache")) + else . end) diff --git a/bazel/pgp/test/fixtures/breakers/passphrase-argv.jq b/bazel/pgp/test/fixtures/breakers/passphrase-argv.jq new file mode 100644 index 0000000000..1e38f9cc62 --- /dev/null +++ b/bazel/pgp/test/fixtures/breakers/passphrase-argv.jq @@ -0,0 +1,4 @@ +.actions |= map( + if .mnemonic == "OpenPGPSign" then + .arguments += ["--passphrase=" + $passphrase] + else . end) diff --git a/bazel/pgp/test/fixtures/example.changes b/bazel/pgp/test/fixtures/example.changes new file mode 100644 index 0000000000..a50837839f --- /dev/null +++ b/bazel/pgp/test/fixtures/example.changes @@ -0,0 +1 @@ +Format: 1.8 diff --git a/bazel/pgp/test/fixtures/example.txt b/bazel/pgp/test/fixtures/example.txt new file mode 100644 index 0000000000..33a9488b16 --- /dev/null +++ b/bazel/pgp/test/fixtures/example.txt @@ -0,0 +1 @@ +example diff --git a/bazel/pgp/test/live_audit.sh b/bazel/pgp/test/live_audit.sh new file mode 100755 index 0000000000..53a9f12a88 --- /dev/null +++ b/bazel/pgp/test/live_audit.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +# +# Captures the real dependency graph of the example signing targets in this +# package, then audits the capture with `//pgp/audit:audit`. +# +# This is the live counterpart to `//pgp/test:audit_test`: it actually +# re-invokes `bazel aquery` so a regression that only shows up in the real +# graph (eg a dropped execution requirement, or a leaked `HOME`) is caught in +# CI. The audit itself still runs through `//pgp/audit:audit`, whose launcher +# invokes jq from runfiles, not from PATH. +# +# Intended to be run with `bazel run //pgp/test:live_audit` from the +# workspace root - it shells out to a fresh `bazel aquery` invocation, so it +# cannot run as a sandboxed `bazel test`. + +set -euo pipefail + +workspace="${BUILD_WORKSPACE_DIRECTORY:?must be run with \`bazel run\`}" +cd "$workspace" + +tmp="$(mktemp -d)" +trap 'rm -rf "$tmp"' EXIT + +pattern="deps(//pgp/test:example_detached) + deps(//pgp/test:example_cleartext) + deps(//pgp/test:example_checksums) + deps(//pgp/test:example_deb_changes)" + +bazel aquery --output=jsonproto --include_artifacts=true \ + --@envoy_toolshed//pgp:key_path=/tmp/nonexistent-key#sha256=0000000000000000000000000000000000000000000000000000000000000000 \ + --@envoy_toolshed//pgp:passphrase_path=/tmp/nonexistent \ + "$pattern" > "$tmp/aquery.json" + +bazel build //pgp/audit:audit +bazel_bin="$(bazel info bazel-bin)" +RUNFILES_DIR="$bazel_bin/pgp/audit/audit.sh.runfiles" \ + "$bazel_bin/pgp/audit/audit.sh" --aquery-json "$tmp/aquery.json" diff --git a/bazel/pgp/test/sign_test.bzl b/bazel/pgp/test/sign_test.bzl new file mode 100644 index 0000000000..097f3bbb5b --- /dev/null +++ b/bazel/pgp/test/sign_test.bzl @@ -0,0 +1,280 @@ +"""Analysis tests for the OpenPGP signing rules.""" + +load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts", "unittest") +load("//pgp/private:sign.bzl", "EXECUTION_REQUIREMENTS", "MNEMONIC") + +KEY_PATH = "/tmp/envoy-toolshed-pgp-test/key.pgp" +KEY_PATH_WITH_FRAGMENT = "/tmp/envoy-toolshed-pgp-test/key.pgp#sha256=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" +KEY_FRAGMENT_DIGEST = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" +PASSPHRASE_PATH = "/tmp/envoy-toolshed-pgp-test/passphrase" + +# Canonical labels - `config_settings` keys are resolved in the repo mapping of +# bazel_skylib, so an apparent label would not resolve. +KEY_FLAG = str(Label("//pgp:key_path")) +PASSPHRASE_FLAG = str(Label("//pgp:passphrase_path")) + +# Execution requirements every signing action must carry. Listed here +# independently of the rule, so that dropping one from the rule fails this +# test. `//pgp/test:audit_test` additionally checks captured `aquery` output. +REQUIRED_EXECUTION_REQUIREMENTS = [ + "no-cache", + "no-remote", + "no-remote-cache", + "no-remote-cache-upload", + "no-remote-exec", +] + +# Environment variables that must never reach a signing action. +_FORBIDDEN_ENV = [ + "GNUPGHOME", + "HOME", + "SSH_AUTH_SOCK", +] + +def _sign_action(env): + actions = [ + action + for action in analysistest.target_actions(env) + if action.mnemonic == MNEMONIC + ] + asserts.equals(env, 1, len(actions), "expected a single %s action" % MNEMONIC) + return actions[0] + +def _execution_requirements_test_impl(ctx): + env = unittest.begin(ctx) + for requirement in REQUIRED_EXECUTION_REQUIREMENTS: + asserts.true( + env, + requirement in EXECUTION_REQUIREMENTS, + "signing actions are missing execution requirement `%s`" % requirement, + ) + return unittest.end(env) + +execution_requirements_test = unittest.make(_execution_requirements_test_impl) + +def _env_test_impl(ctx): + env = analysistest.begin(ctx) + action = _sign_action(env) + for name in _FORBIDDEN_ENV: + asserts.true( + env, + name not in action.env, + "%s action leaks `%s` into its environment" % (MNEMONIC, name), + ) + asserts.equals( + env, + {"PATH": "/usr/bin:/bin"}, + action.env, + "%s action environment is not the expected minimal PATH" % MNEMONIC, + ) + return analysistest.end(env) + +env_test = analysistest.make( + _env_test_impl, + config_settings = { + KEY_FLAG: KEY_PATH, + PASSPHRASE_FLAG: PASSPHRASE_PATH, + }, +) + +def _args_test_impl(ctx): + env = analysistest.begin(ctx) + action = _sign_action(env) + argv = action.argv + asserts.true( + env, + "--require-encrypted-key" in argv, + "%s action does not require an encrypted key" % MNEMONIC, + ) + asserts.true( + env, + "--passphrase-file" in argv, + "%s action does not pass a passphrase file" % MNEMONIC, + ) + asserts.true( + env, + PASSPHRASE_PATH in argv, + "%s action does not pass the configured passphrase path" % MNEMONIC, + ) + asserts.true( + env, + "--key" in argv, + "%s action does not pass a key path" % MNEMONIC, + ) + asserts.equals( + env, + KEY_PATH, + argv[argv.index("--key") + 1], + "%s action does not pass the configured key path" % MNEMONIC, + ) + if ctx.attr.expect_key_sha256: + asserts.true( + env, + "--key-sha256" in argv, + "%s action expected --key-sha256" % MNEMONIC, + ) + asserts.equals( + env, + ctx.attr.expect_key_sha256, + argv[argv.index("--key-sha256") + 1], + "%s action passed wrong key sha256" % MNEMONIC, + ) + else: + asserts.false( + env, + "--key-sha256" in argv, + "%s action should not pass --key-sha256 when no fragment is configured" % MNEMONIC, + ) + asserts.equals( + env, + ctx.attr.mode, + argv[argv.index("--mode") + 1], + "%s action signs in the wrong mode" % MNEMONIC, + ) + return analysistest.end(env) + +args_test = analysistest.make( + _args_test_impl, + attrs = { + "expect_key_sha256": attr.string(), + "mode": attr.string(mandatory = True), + }, + config_settings = { + KEY_FLAG: KEY_PATH, + PASSPHRASE_FLAG: PASSPHRASE_PATH, + }, +) + +args_with_fragment_test = analysistest.make( + _args_test_impl, + attrs = { + "expect_key_sha256": attr.string(), + "mode": attr.string(mandatory = True), + }, + config_settings = { + KEY_FLAG: KEY_PATH_WITH_FRAGMENT, + PASSPHRASE_FLAG: PASSPHRASE_PATH, + }, +) + +def _inputs_test_impl(ctx): + env = analysistest.begin(ctx) + action = _sign_action(env) + inputs = [f.short_path for f in action.inputs.to_list()] + src_short_path = ctx.file.src.short_path + signer = ctx.attr.signer[DefaultInfo].files_to_run.executable + tool_inputs = { + f.short_path: True + for f in ctx.attr.signer[DefaultInfo].default_runfiles.files.to_list() + } + if signer: + tool_inputs[signer.short_path] = True + asserts.true( + env, + src_short_path in inputs, + "expected %s in action inputs: %s" % (src_short_path, inputs), + ) + non_tool_inputs = [f for f in inputs if f not in tool_inputs] + asserts.equals( + env, + [src_short_path], + non_tool_inputs, + "signing action inputs must contain exactly src and tool files (no key): got %s" % inputs, + ) + return analysistest.end(env) + +inputs_test = analysistest.make( + _inputs_test_impl, + attrs = { + "signer": attr.label(default = ":stub_signer"), + "src": attr.label(mandatory = True, allow_single_file = True), + }, + config_settings = { + KEY_FLAG: KEY_PATH, + PASSPHRASE_FLAG: PASSPHRASE_PATH, + }, +) + +def _no_key_test_impl(ctx): + env = analysistest.begin(ctx) + asserts.expect_failure(env, "No key path configured") + return analysistest.end(env) + +no_key_test = analysistest.make( + _no_key_test_impl, + expect_failure = True, + config_settings = { + KEY_FLAG: "", + PASSPHRASE_FLAG: PASSPHRASE_PATH, + }, +) + +def _relative_key_test_impl(ctx): + env = analysistest.begin(ctx) + asserts.expect_failure(env, "is not absolute") + return analysistest.end(env) + +relative_key_test = analysistest.make( + _relative_key_test_impl, + expect_failure = True, + config_settings = { + KEY_FLAG: "relative/key.pgp", + PASSPHRASE_FLAG: PASSPHRASE_PATH, + }, +) + +def _bad_key_fragment_test_impl(ctx): + env = analysistest.begin(ctx) + asserts.expect_failure(env, "Invalid sha256 fragment") + return analysistest.end(env) + +bad_key_fragment_test = analysistest.make( + _bad_key_fragment_test_impl, + expect_failure = True, + config_settings = { + KEY_FLAG: "/tmp/key#md5=1234", + PASSPHRASE_FLAG: PASSPHRASE_PATH, + }, +) + +def _no_passphrase_test_impl(ctx): + env = analysistest.begin(ctx) + asserts.expect_failure(env, "No passphrase path configured") + return analysistest.end(env) + +no_passphrase_test = analysistest.make( + _no_passphrase_test_impl, + expect_failure = True, + config_settings = { + KEY_FLAG: KEY_PATH, + PASSPHRASE_FLAG: "", + }, +) + +def _relative_passphrase_test_impl(ctx): + env = analysistest.begin(ctx) + asserts.expect_failure(env, "is not absolute") + return analysistest.end(env) + +relative_passphrase_test = analysistest.make( + _relative_passphrase_test_impl, + expect_failure = True, + config_settings = { + KEY_FLAG: KEY_PATH, + PASSPHRASE_FLAG: "passphrase", + }, +) + +def _passphrase_fragment_test_impl(ctx): + env = analysistest.begin(ctx) + asserts.expect_failure(env, "passphrase digest is an oracle") + return analysistest.end(env) + +passphrase_fragment_test = analysistest.make( + _passphrase_fragment_test_impl, + expect_failure = True, + config_settings = { + KEY_FLAG: KEY_PATH, + PASSPHRASE_FLAG: "/tmp/passphrase#sha256=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", + }, +) diff --git a/bazel/pgp/test/signer_test.sh b/bazel/pgp/test/signer_test.sh new file mode 100755 index 0000000000..722c14aaff --- /dev/null +++ b/bazel/pgp/test/signer_test.sh @@ -0,0 +1,157 @@ +#!/usr/bin/env bash +# +# Integration test for the signer CLI contract. +# +# Generates a passphrase-encrypted key with `sq` at test time (no key material +# is ever committed), signs in each mode, verifies the signatures, and asserts +# that the signer refuses to use an unencrypted key. +# +# Skipped if no `sq` is available - the default toolchain binary is not +# fetched by default (see //pgp:extensions.bzl). + +set -euo pipefail + +SQ="${SQ:-}" +if [[ -z "$SQ" ]]; then + SQ="$(command -v sq || true)" +fi + +if [[ -z "$SQ" ]]; then + echo "SKIP: no \`sq\` binary found (set SQ to run this test)" + exit 0 +fi + +SIGNER="$(dirname "$0")/../private/signer.sh" +if [[ ! -f "$SIGNER" ]]; then + SIGNER="pgp/private/signer.sh" +fi + +TMP="$(mktemp -d)" +trap 'rm -rf "$TMP"' EXIT + +PASSPHRASE_FILE="${TMP}/passphrase" +KEY="${TMP}/key.pgp" +UNENCRYPTED_KEY="${TMP}/unencrypted-key.pgp" +DATA="${TMP}/data.txt" + +sq () { + "$SQ" --batch --home none --cert-store none --key-store none "$@" +} + +signer () { + SQ="$SQ" bash "$SIGNER" "$@" +} + +printf %s "test-passphrase-$$" > "$PASSPHRASE_FILE" +chmod 600 "$PASSPHRASE_FILE" +echo "some data" > "$DATA" + +sq key generate --own-key --without-password --no-userids \ + --rev-cert "${UNENCRYPTED_KEY}.rev" --output "$UNENCRYPTED_KEY" > /dev/null +sq key generate --own-key --new-password-file "$PASSPHRASE_FILE" \ + --no-userids --rev-cert "${KEY}.rev" --output "$KEY" > /dev/null +failed=0 + +check () { + local msg="$1" + shift + if "$@"; then + echo "ok: ${msg}" + else + echo "FAIL: ${msg}" >&2 + failed=1 + fi +} + +check_fails () { + local msg="$1" + shift + if "$@" > "${TMP}/output" 2>&1; then + echo "FAIL: ${msg}" >&2 + failed=1 + else + echo "ok: ${msg}" + fi +} + +# Detached signature. +check "detached signature created" \ + signer --mode detached --key "$KEY" \ + --passphrase-file "$PASSPHRASE_FILE" --require-encrypted-key \ + --armor --out "${TMP}/data.txt.asc" "$DATA" +check "detached signature verifies" \ + sq verify --signature-file "${TMP}/data.txt.asc" \ + --signer-file "$KEY" "$DATA" + +# Cleartext signature. +check "cleartext signature created" \ + signer --mode cleartext --key "$KEY" \ + --passphrase-file "$PASSPHRASE_FILE" --require-encrypted-key \ + --out "${TMP}/data.txt.cleartext" "$DATA" +check "cleartext signature is a cleartext signed message" \ + grep -q -- "-----BEGIN PGP SIGNED MESSAGE-----" \ + "${TMP}/data.txt.cleartext" +check "cleartext signature verifies" \ + sq verify --cleartext --signer-file "$KEY" \ + "${TMP}/data.txt.cleartext" + +# Inline signature. +check "inline signature created" \ + signer --mode inline --key "$KEY" \ + --passphrase-file "$PASSPHRASE_FILE" --require-encrypted-key \ + --armor --out "${TMP}/data.txt.inline" "$DATA" +check "inline signature verifies" \ + sq verify --message --signer-file "$KEY" \ + --output /dev/null "${TMP}/data.txt.inline" + +# --key-sha256 matching. +calc_sha256 () { + if command -v sha256sum > /dev/null 2>&1; then + sha256sum "$1" | awk '{print $1}' + else + shasum -a 256 "$1" | awk '{print $1}' + fi +} +KEY_SHA256="$(calc_sha256 "$KEY")" + +check "signature created with matching --key-sha256" \ + signer --mode detached --key "$KEY" --key-sha256 "$KEY_SHA256" \ + --passphrase-file "$PASSPHRASE_FILE" --require-encrypted-key \ + --armor --out "${TMP}/data_sha.txt.asc" "$DATA" + +# --key-sha256 mismatching. +BAD_SHA256="0000000000000000000000000000000000000000000000000000000000000000" +check_fails "mismatched --key-sha256 is rejected" \ + signer --mode detached --key "$KEY" --key-sha256 "$BAD_SHA256" \ + --passphrase-file "$PASSPHRASE_FILE" --require-encrypted-key \ + --armor --out "${TMP}/rejected_sha.asc" "$DATA" +check "mismatch error is explicit" \ + grep -q "key digest mismatch" "${TMP}/output" +check "no output written for mismatched sha256" \ + test ! -e "${TMP}/rejected_sha.asc" + +# Relative --key path. +check_fails "relative --key path is rejected" \ + signer --mode detached --key "relative/path/key.pgp" \ + --passphrase-file "$PASSPHRASE_FILE" --require-encrypted-key \ + --armor --out "${TMP}/rejected_relative.asc" "$DATA" +check "relative key path error points at --@envoy_toolshed//pgp:key_path" \ + grep -q "key_path" "${TMP}/output" +check "no output written for relative key path" \ + test ! -e "${TMP}/rejected_relative.asc" + +# Unencrypted keys must be rejected. +check_fails "unencrypted key is rejected" \ + signer --mode detached --key "$UNENCRYPTED_KEY" \ + --passphrase-file "$PASSPHRASE_FILE" --require-encrypted-key \ + --armor --out "${TMP}/rejected.asc" "$DATA" +check "rejection is explicit" \ + grep -q "REFUSING TO SIGN" "${TMP}/output" +check "no output was written for a rejected key" \ + test ! -e "${TMP}/rejected.asc" + +if [[ "$failed" -ne 0 ]]; then + exit 1 +fi + +echo "signer integration test passed" diff --git a/bazel/pgp/test/stub_signer.sh b/bazel/pgp/test/stub_signer.sh new file mode 100755 index 0000000000..98ce96eb22 --- /dev/null +++ b/bazel/pgp/test/stub_signer.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash +# +# Stub signer used by the analysis tests. +# +# It implements the argument contract of the real signer but performs no +# cryptography - the analysis tests only need a registered toolchain. + +set -euo pipefail + +MODE= +KEY= +PASSPHRASE_FILE= +OUT= +INPUTS=() + +usage () { + echo "usage: $0 --mode MODE --key KEY [--key-sha256 HEX]" \ + "--passphrase-file PATH --out OUT [--armor]" \ + "[--require-encrypted-key] INPUT" >&2 + exit 2 +} + +while [[ $# -gt 0 ]]; do + case "$1" in + --mode) + MODE="$2" + shift 2 + ;; + --key) + KEY="$2" + shift 2 + ;; + --key-sha256) + # Accepted for contract parity; the stub does no verification. + shift 2 + ;; + --passphrase-file) + PASSPHRASE_FILE="$2" + shift 2 + ;; + --out) + OUT="$2" + shift 2 + ;; + --armor|--require-encrypted-key) + shift + ;; + -*) + echo "stub signer: unknown option: $1" >&2 + usage + ;; + *) + INPUTS+=("$1") + shift + ;; + esac +done + +if [[ -z "$MODE" || -z "$KEY" || -z "$PASSPHRASE_FILE" || -z "$OUT" ]]; then + echo "stub signer: incomplete arguments" >&2 + usage +fi + +if [[ ${#INPUTS[@]} -ne 1 ]]; then + echo "stub signer: expected exactly one input, got ${#INPUTS[@]}" >&2 + usage +fi + +echo "STUB SIGNATURE (${MODE})" > "$OUT" diff --git a/bazel/pgp/toolchain.bzl b/bazel/pgp/toolchain.bzl new file mode 100644 index 0000000000..5979627c68 --- /dev/null +++ b/bazel/pgp/toolchain.bzl @@ -0,0 +1,52 @@ +"""Toolchain for hermetic OpenPGP signing. + +The toolchain provides an executable implementing the signer CLI contract +documented in `//pgp:README.md`: + +``` +signer --mode {detached|cleartext|inline} \\ + --key \\ + [--key-sha256 ] \\ + --passphrase-file \\ + --require-encrypted-key \\ + --out \\ + [--armor] \\ + +``` + +Any implementation of that contract can be dropped in without changing the +rules - the default implementation wraps Sequoia PGP's `sq`. +""" + +PgpSignerInfo = provider( + doc = "Information about an OpenPGP signer implementation.", + fields = { + "runfiles": "runfiles required by the signer executable.", + "signer": "File: executable implementing the signer CLI contract.", + }, +) + +def _pgp_toolchain_impl(ctx): + default = ctx.attr.signer[DefaultInfo] + executable = default.files_to_run.executable + if not executable: + fail("`signer` (%s) does not provide an executable" % ctx.attr.signer.label) + return [platform_common.ToolchainInfo( + pgp_signer = PgpSignerInfo( + signer = executable, + runfiles = default.default_runfiles, + ), + )] + +pgp_toolchain = rule( + implementation = _pgp_toolchain_impl, + doc = "Declares an OpenPGP signer implementation for `//pgp:toolchain_type`.", + attrs = { + "signer": attr.label( + doc = "Executable implementing the signer CLI contract.", + mandatory = True, + executable = True, + cfg = "exec", + ), + }, +)