diff --git a/.github/dependabot.yml b/.github/dependabot.yml index ea45a148f1..2940763d6d 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -87,3 +87,20 @@ updates: schedule: interval: "monthly" day: "thursday" + + # Semgrep and its hash-locked Python dependencies require reviewed PRs. + - package-ecosystem: "pip" + directory: "/.github/requirements" + schedule: + interval: "monthly" + open-pull-requests-limit: 5 + - package-ecosystem: "docker" + directory: "/" + schedule: + interval: "monthly" + open-pull-requests-limit: 5 + - package-ecosystem: "docker" + directory: "/.github/packaging" + schedule: + interval: "monthly" + open-pull-requests-limit: 5 diff --git a/.github/packaging/Dockerfile.apk b/.github/packaging/Dockerfile.apk new file mode 100644 index 0000000000..62dc7156de --- /dev/null +++ b/.github/packaging/Dockerfile.apk @@ -0,0 +1,3 @@ +FROM alpine:3.24@sha256:28bd5fe8b56d1bd048e5babf5b10710ebe0bae67db86916198a6eec434943f8b +RUN apk add --no-cache bash curl openssl +CMD ["tail", "-f", "/dev/null"] diff --git a/.github/packaging/Dockerfile.deb b/.github/packaging/Dockerfile.deb new file mode 100644 index 0000000000..62fb14e7d3 --- /dev/null +++ b/.github/packaging/Dockerfile.deb @@ -0,0 +1,3 @@ +FROM debian:12@sha256:6ebd97fa83deb272194a2cf015b3d26a4d538e9ad3a7a79d544c8af5b0a01443 +RUN apt-get update && apt-get install -y --no-install-recommends systemd systemd-sysv dbus curl openssl ca-certificates adduser && rm -rf /var/lib/apt/lists/* +CMD ["/lib/systemd/systemd"] diff --git a/.github/packaging/Dockerfile.rpm b/.github/packaging/Dockerfile.rpm new file mode 100644 index 0000000000..59a0bee643 --- /dev/null +++ b/.github/packaging/Dockerfile.rpm @@ -0,0 +1,3 @@ +FROM rockylinux/rockylinux:9@sha256:8101994123cf3d0a8fee517bee7f39e555c7d92bd2d9eb3303cc988a0eeed00f +RUN dnf install -y systemd dbus openssl shadow-utils curl-minimal && dnf clean all +CMD ["/usr/sbin/init"] diff --git a/.github/requirements/firefox.env b/.github/requirements/firefox.env new file mode 100644 index 0000000000..9406f3827f --- /dev/null +++ b/.github/requirements/firefox.env @@ -0,0 +1,4 @@ +# Mozilla release archive, Linux x86_64 en-US. Review version and digest together. +# https://archive.mozilla.org/pub/firefox/releases/155.0.1/SHA512SUMS +FIREFOX_VERSION=155.0.1 +FIREFOX_SHA512=da23025495aa3a2b154cff7c6464fa8bc31ca0c683b378c34b9dced9f33b6e657537c0b5fc44e98bce742bda8e3c58a0a571d1ccd849bf41031881cd36dfba1b diff --git a/.github/requirements/semgrep.in b/.github/requirements/semgrep.in new file mode 100644 index 0000000000..493464ab14 --- /dev/null +++ b/.github/requirements/semgrep.in @@ -0,0 +1 @@ +semgrep==1.176.1 diff --git a/.github/requirements/semgrep.txt b/.github/requirements/semgrep.txt new file mode 100644 index 0000000000..4188dc0bf9 --- /dev/null +++ b/.github/requirements/semgrep.txt @@ -0,0 +1,1082 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile --python-version 3.12 --python-platform x86_64-unknown-linux-gnu --generate-hashes .github/requirements/semgrep.in -o .github/requirements/semgrep.txt +annotated-types==0.8.0 \ + --hash=sha256:13b2beaad985e05e2d6407ee4c4f35590b11f8d693a258a561055cac8f64cab7 \ + --hash=sha256:f072f4d804ea359e4eaf198b1af7a8b0943881a87f31bb764f8bf219bb9419e0 + # via pydantic +anyio==4.15.1 \ + --hash=sha256:6152fdbbf9a77fdec97731721bebf7c4c44f7c29b424b0065826173efc7ed101 \ + --hash=sha256:9f28306018cbd6d329e64a36d58256edff76dd996fe423bc957326e578b82a94 + # via + # httpx + # mcp + # sse-starlette + # starlette +attrs==26.1.0 \ + --hash=sha256:c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309 \ + --hash=sha256:d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32 + # via + # glom + # jsonschema + # referencing + # semgrep +boltons==21.0.0 \ + --hash=sha256:65e70a79a731a7fe6e98592ecfb5ccf2115873d01dbc576079874629e5c90f13 \ + --hash=sha256:b9bb7b58b2b420bbe11a6025fdef6d3e5edc9f76a42fb467afe7ca212ef9948b + # via + # face + # glom + # semgrep +bracex==3.0.1 \ + --hash=sha256:4e38e32392e4a4780fe15d644bfc7c8514057cfc3861e060b11814ce829c25e4 \ + --hash=sha256:6523ad83aeb5098a4ee597cff0f964442ff74e460bd3fafaffab6a013ff2288c + # via wcmatch +certifi==2026.7.22 \ + --hash=sha256:62f22742b58a1a33014a2b6b706588a8d7e2a88ae7bd1a6ebe8c992928483775 \ + --hash=sha256:741e2c3b351ddf169a738da9f2c048608ff7f2c5cc02f1ebc6b118bb090d5d55 + # via + # httpcore + # httpx + # requests +cffi==2.1.1 \ + --hash=sha256:046bfc24911b37851ee1b51aab8bffe713d89c68c6a057b09484ce9fd5f69b4e \ + --hash=sha256:06c72bb76605a4b0cd0aad6930b69d4baf7dd5d806cfc409b824191099700e66 \ + --hash=sha256:0beceaabe56af686895136a2de78db54ecd8e4046b236b8fd6d6cb61389e9bf2 \ + --hash=sha256:154852545011f779917b11c78db2358d095da62a9a172b78ad0a583ee5adc0d0 \ + --hash=sha256:194cffa889098ced9976c3fc6340305e43f6303657d298da55366907c05c22d6 \ + --hash=sha256:19ee6127ee34de7d83ce3d371ebc5ed91addbdcc39f9ab15ce4eb35a4e534971 \ + --hash=sha256:1a18a57b58cfb21fc28d72e876acf10eaed67a1ed96226f92af4df681d571c4c \ + --hash=sha256:1aa5645c30469b09530c4ebca77ebf8f17618293c58f8549cb1a543a50236e7d \ + --hash=sha256:1dea0e4d7d4f11f619fe8c1d76caf49e24405b4b5743c0e3be16a500ecd930c9 \ + --hash=sha256:208f941bb9d18e768138677f0a6d2ce01f590df56043dda1df1535ac57c88517 \ + --hash=sha256:210019b6c7cf07f081b4c54635c8cf744377001350e29cc0f81c4377b4797735 \ + --hash=sha256:246fa40ce8645a614ff682e0b70f37134e460eaf93a775e0cbe3cca585a67a80 \ + --hash=sha256:25792eac27877609e7bb06d42ff88278a6624fff2ba9bbb523c09616b117e80f \ + --hash=sha256:27350daa11d4f10c540e6e89dada4c54feb7256ad03e9a4dc075ebad7ba360d1 \ + --hash=sha256:28907ab9bfb6aa13184cfc17c6b8e1023c5ab6fd7076d8c20a35e59fe04f8f29 \ + --hash=sha256:2ae64be792b8966f2c69538199728b290e34726562896df1e5dc8ffd8d8188e8 \ + --hash=sha256:31348097ff5bbe827ccc41795d4dd099d9f0625e7def00ee653c137a490c2a6c \ + --hash=sha256:3143d81e29e1e20a9ce10901ec369012947876596f75a222235965f2b7ae832e \ + --hash=sha256:3222ba5d678f80a030e6afbcc33dc1ae5cb45facabb61cee2c7016b8432fde48 \ + --hash=sha256:3311ed60d36f83378794e1009ac6258bafbf81f7888b4caa7b35a521e3f95813 \ + --hash=sha256:334644fbac4eff73d985a17a91226df55d0f394160c4cfb880e084c8f7161cac \ + --hash=sha256:34e261f78cb6ceaaa36f42f2613f4380d94d9c759a9c73c769ee6e0247364632 \ + --hash=sha256:363e05fa78e15116c3c32c210ee36884fd6b9afa6d440e47112c3bd511d64cb6 \ + --hash=sha256:398aff33cee2767e3e781d2554c54bd0dff386bb437581e0d8011fde1a942ec1 \ + --hash=sha256:3d22a20b1fb1632cc72c22f95f7b0d2961c3e1c235f245ba4c606c4771035659 \ + --hash=sha256:42a494cee34437f05546455144f2b5d9ac09b1face62bcfce597d2e521066688 \ + --hash=sha256:42e2f76b9455f5a9a844f770bf3e200ed3da0e15f5df3db9c31fe80b04b3d004 \ + --hash=sha256:42f6930c31dc7f50732c9ae793c2786c7b6b044195967bbdde40bb9be81c4cc0 \ + --hash=sha256:456a61fa52d579ebf9df2e9552ead5129855dbaff6c1e5a9b1bc408809bdc062 \ + --hash=sha256:471cee653ae88de62096552e6d24ccb4a5adb8c8c9f10b5054d0122c15bf2779 \ + --hash=sha256:49cbc70e6542d4ccccb936558d1064a8012541e78f821f955cff24e357776c94 \ + --hash=sha256:4a7c934f7360e8cd64fe9efadcbd10c7c6364f531e432b9a4bf5ccbc9e0e8b50 \ + --hash=sha256:4be96343e422f2dfcd12ab5c9f5aebe03f82f737c6bffeca6830b3875cb44aab \ + --hash=sha256:4f42141fc14250de6dde5ee7ea4432be017252d91f19c5ad043c084cea629cac \ + --hash=sha256:507a24c282e0f42f8ed737cf048572cbf580468da5555764a8331735e9c736b6 \ + --hash=sha256:51b31d1c98274844cfd7838ce00bfc27c7423a4dc00fc0772fc3331c2cc90676 \ + --hash=sha256:58acb8ab8e295e6c5ea12f888cbb13cf21511ef2a3303a23f4325c29d17fe5c1 \ + --hash=sha256:5a59cc1c4442bc3d5c703bf720b51138d0bfc173618807c9ee2490a7541dd3d9 \ + --hash=sha256:5bb4e7ea95dcd6a014a6fef62e62467d67d8e582326443f3d68e71d6320a9fcf \ + --hash=sha256:5c58fe613dc5e5336357eff555824a314d8e43282600435c8d1cb6a7a2fedd13 \ + --hash=sha256:5e7cecbaadb83884793e05828cee59b210b24583b9c7425d0ba6a754fe22eb4e \ + --hash=sha256:616f097f2fe415bc92a247f02e11f634e1f9e9a83d327e3c915c15089c87869e \ + --hash=sha256:63bbfd5ded17c4840ac07cd8f1c21ba9d9708141f840b324f422f41b207e3973 \ + --hash=sha256:64faea20f4e2613363a1a9b9c7dd73058f3ecd00133a511e72ad7c511658f527 \ + --hash=sha256:661c298b4821edebead0c91edd2b00374d67ad7c5a1f7a91d4442633b79d6a72 \ + --hash=sha256:68e62fe11f30d5ca8289242866f0a5291402d8529ca2178ab8afc5c9694ae890 \ + --hash=sha256:6a8dddef476fab96d066d578fc88526767b836ab5ab21754e1d5bf3879c31c7c \ + --hash=sha256:6e192623c49c94421616a5778fba35cf0d5a8d000650c1967ef4448ee5cdd990 \ + --hash=sha256:7225e4514edb64eb6740324353e0da0711954fd8d7da4576755b1c6e09b697cd \ + --hash=sha256:75f80557d1389eddbd0de2681f6a390a0c5338c31ddaa821381c203fc3fd50d9 \ + --hash=sha256:770de9db11e84213beec501cfcaa013b019820ca881e03344dea5844f7876d94 \ + --hash=sha256:7750c6449dff7864bb9bb27ddfb0267756189201a3afc911d82b3caacd70dfc3 \ + --hash=sha256:7bde5e4cc5c10140859842b9d383af292b22639a4dffb725314baf45968cef80 \ + --hash=sha256:7ce713ace7c0e4520535b42b77eaa742c16dab813978064913e5a3cf82973b41 \ + --hash=sha256:7da0c5eff80f0197f3b3d1232ec5a682a9325f4ae9016a78f5f5ca35f9ced1f5 \ + --hash=sha256:7dbb61fe3a7699468030f71bbe5f8a0e326a151daa91beb11a6fc1f980c55e1c \ + --hash=sha256:811bd1e21d32de12efca32393a0ab3f5133b54fce9bd44b8bd77ab07da14bf6a \ + --hash=sha256:8ef53b2de9bcb9197d31854256575d59dbac0cba72ac627bb291ef5eceb74be4 \ + --hash=sha256:937c0052c05a31ca1daf18de3158eed4dbfcb9cc107adbea227728d647be701e \ + --hash=sha256:9d2055050ea716bd38b7f7f1579c275386646b4894c155a3e2f3cd62ed41b7c6 \ + --hash=sha256:9f8d177621de5cb38ee3e731eda45d421db093ec0739f46a5594babda7987a98 \ + --hash=sha256:a2d7755bef5a12ed488f4ef1f1b69ee9191d7396083b755a5d2295f6edb4768b \ + --hash=sha256:a48d62ab9d6f4f98c983223a547af44be6ca3691074c31cecced6facd3ba2dc1 \ + --hash=sha256:a4f00aa42f75d6e4595e8866e748cc1705adc0cddfeb2ca86d0d03993d63ba03 \ + --hash=sha256:a6e721d4b0e45d5b65e87534470e67b18dcd092c83f68fba09f152b9cbc061af \ + --hash=sha256:a730a083190634c65cca36ba5f489531576ebd79bcd5c8e172130f6453127231 \ + --hash=sha256:a931079504ecc49efed7744c476a5c343a92fabf66dec2db95edb1b2fdc770e2 \ + --hash=sha256:aa9511c62d14da7aacc9b4bf51f3f697a621e83b2d6919008243c3aad168eea3 \ + --hash=sha256:ab36d55f9ed2d067327667c2fea18dda018eb628dd6347aa01dda6cf1f5d3836 \ + --hash=sha256:ad2c86c495b899d862ea0f4b42891b8713a3bd45dd4105c7fd51c2a72f39f3a5 \ + --hash=sha256:aeae0e330c9f6acd681f647d46cefd30c29f93e3392882e792e82080c9691399 \ + --hash=sha256:b0431303acaea1089ad4b3e9ce4e6518193def1118d4073ca848635ee4ea2e96 \ + --hash=sha256:b5bdfd1c873d4e093aabc0ca84c4ca6dbc4f752afb5c86f146d9742580c9da2e \ + --hash=sha256:baed1e86cc735622097354b9d1281406caf42ff42a886d29faa8e8d1630333be \ + --hash=sha256:c1453022f490d2459a11819d83ad1d586e9ff65a12ac3e705ffebd46d3685dcf \ + --hash=sha256:c26608d2222fb1e94487e4a387d85f13eb55d5ed725cb25a0c589ac4ee60e7bc \ + --hash=sha256:c7659f22557c5a0bc4855cd635f55edec690cc008a40768527762cb9fb263455 \ + --hash=sha256:c8c69575568085ba0b1b10c0249d779a214aea6f6522e949a0fc9fb0fcb449d0 \ + --hash=sha256:c8d2c9fd1f2d16f780d15127abb050d13d1a76c03a4bd87d7e4980e45e511e12 \ + --hash=sha256:ca82be1a1d406ecfe1d25dc16cb33488e5a16bf4438c9fb590484ea29d92478b \ + --hash=sha256:cc572dace3f60ef98d7b12ff411d20f5362feb31a0439eab0085bbfd349982d7 \ + --hash=sha256:d18e5ac0f2f03f4f518d3e23db0f0cad7faa1da8620e9c09461d443bbf6e6692 \ + --hash=sha256:d28630f5854ab07ab1fd4aba756de52326c82e6be15d414b12793f1975048b54 \ + --hash=sha256:d9c275eaacd24aa73f94ffd6de08fc3f932424d8b6c376f4bed7cde376fe7bc3 \ + --hash=sha256:da0e573f9f97159390c89d9f1a9e41908b66d408cc5b58d08cf3847d844c531b \ + --hash=sha256:dd31f52ea1086513bb9df30f8fcee9b8918323ae067a3d5b78bc826a000712be \ + --hash=sha256:dddad92b554513a31f272570678ba307fb9f618f05e3d4a5eacafff9eae03e1d \ + --hash=sha256:df423d40ee8654634421812bc3b196da3f9bd7d32929da813f8394c4348a5358 \ + --hash=sha256:df913725b79db7bcf03448f36b7bf8815363417d5b58deecf9305e3e30f0f21a \ + --hash=sha256:e0bcb7e0f677f543555d2adff3bf19c05f66cdb4796e5ff602442ab2fe3c4ef7 \ + --hash=sha256:e2d65b31f36619cda3999b78b2aa9632e76b78448e7a56fc4240824200e7c4fc \ + --hash=sha256:e6e8cff14d6fb0be70a09c0bdc58096f501952d04624ebf867e0e56da2df8960 \ + --hash=sha256:f16c709686a78c727bbbf059f92b0bf41c6fc60deec706d2dc19f529175a6125 \ + --hash=sha256:f24fb43132a4c6b4cb4eb029492919b2db645be6808d738f244fd146c03c32cb \ + --hash=sha256:f53e442b08449d42821fa4a4fba000095af9f62742a500f978a9f557ec44339a \ + --hash=sha256:f5cfbc5fe74540d335175b656c725d74d90e3730c626d92575eea35029d9afaa \ + --hash=sha256:f81b3b8f3d4e343550fa4baa0e479bba9f2d29ce9c2e9b51d1ce1718d7442fcf \ + --hash=sha256:f8ec5e643a9a937f64e1999eb9f75d072263751912dc5cd06d3c85f8f44be7c3 \ + --hash=sha256:fb92203a88b3d3053034db775110081c49d28be6551923805e039924093761e4 \ + --hash=sha256:fcd22650c908d7b7da162bbfaab594a1227a15d1643a98c68b122ac642fa2264 + # via cryptography +charset-normalizer==3.5.1 \ + --hash=sha256:00668ebb0609751758682eb0b5857e7c35b9f00e84dfdef062e103244ec94d45 \ + --hash=sha256:012a22b88a77ca2e59b98ac5889b0deb604147666032f45e6d6e217634d2550d \ + --hash=sha256:01e93745f7f219b703b60ba7afead36cfc4242782be5af484673fc500df12da5 \ + --hash=sha256:04368edf83514385ffc3e1cfd4546e595f4f1272dd23ba437a93a9cc3741d47b \ + --hash=sha256:0722590aabf9dc6a6c0343d523c05458fa2b5047dbe6302fd526bb570600753f \ + --hash=sha256:07ffd07412fc5d5e84cd8952acf9ff7e4ed7a708e69d1bada19d8ba91711353f \ + --hash=sha256:09a7bba9f739468c8e78c36a75c33768e53cb1959fc638f510454c14683f00d5 \ + --hash=sha256:0b2b1b3fa5670c127b246df1d0c059defd41f689a868a3b9d79df9b1cac42d22 \ + --hash=sha256:0c6dfb5ca6723eeed15aa8e564a014d69fcb8812f94eef11fe3631e0508199f5 \ + --hash=sha256:0d929fc574b4d6fd9e7c0f5c2ede8716a41911923aa7fa5fce38e0818aa4a1ac \ + --hash=sha256:13e3afe97712e8887cd516e960c63f0b93122971e5b5e4b2622fe7701771e838 \ + --hash=sha256:15f024313246a4ed976c60f440bb8d257815513a681d212ff74fd46f7d715a90 \ + --hash=sha256:195ce897c6153c0700078142cf8efe3e6454ca4cf4357499e4078dfd83396626 \ + --hash=sha256:19a3dd5aa73cef1c99687c4fc57db016a9c17104ae1185da88ba566a5d3bebe4 \ + --hash=sha256:1d1c7a53a6c2103925cdd6d7229f8c567379f211c869793df679f2e9f738c369 \ + --hash=sha256:1f5883d77fd409a261abb5dc8ccbe335720d798b1de4abb3b1d47ccbbc76b53b \ + --hash=sha256:21b82d8082f6f5e7f456ef0bd16323d08de1266efbfeb476e64b2a91d1471a4e \ + --hash=sha256:252d099029bcbea642f2a06c4ed5046bdf8b5a8150b64afa5e027e88b106e5ee \ + --hash=sha256:256dd4d85d9e4dc595e2bc983c980e73f62ddeb3165c58b4c3dfe78c5c8548c1 \ + --hash=sha256:26422d45fd13551cf564c58932f7d72b4f58b93b0fcf18c35ba6be12b46bb102 \ + --hash=sha256:2679de311c7946dde5d3b6f44941844133ff5c7cb86099c0061ab1e8901c20a8 \ + --hash=sha256:29880d17a8eb0b5cfdfd8944b468322928059aa35f1f5fa8ff22b149ec0b42f8 \ + --hash=sha256:2bced4061f000f7187254a02ad3433ae17eaf991747ceea2f478422590a5bba9 \ + --hash=sha256:2e9cf9253119d8e5d111f05d71626786fd3d6193817316eab1ca088cdb8593cf \ + --hash=sha256:2f06b7eae9dbe77fe1d644ca244dad508de8d302870a43f3c559b521270938a0 \ + --hash=sha256:2f293479cce755c75f1697e87c409b7ae4c555c7dfecb6e988ad13abba943031 \ + --hash=sha256:329fc3ccb63ad22d867d84c2adea759a64079a37ba4a343433b02c7a2816871e \ + --hash=sha256:343fb4f2821043bd87095f7b08a1a181febc8e36ac64212143bbfd0a0e1bc235 \ + --hash=sha256:3588e376b3ea2eea84976f67273d679f229e24c66dce7b82ae45aef04ff6e072 \ + --hash=sha256:35aea775dc2bd5f54cd84a1cd2696cc3207c479cb9cf0bd346f0d343e4300ddb \ + --hash=sha256:35fe081843b35aad20ffeccec3eeffbe637b15d14f3fb22cc1b59cd8ec17e93c \ + --hash=sha256:36047af20e17097c3bb9476c2b7655f2f7aa51322c0ba58c07695bedf755a950 \ + --hash=sha256:3617ac3cfd8b9888f145ad89dd6e692285834b0201c6074a5eeaad3fd4d668c2 \ + --hash=sha256:366ec70f5547c640d3ce1985722490f23faf4eb5216a7eeba78277490e78dacb \ + --hash=sha256:394fea06235c8543390050ed5f529187074b029fb027213f6c46ac11ab5d950e \ + --hash=sha256:3d27167433c0d5f18dc850f07d0b3816221984fecdc405d6c157a6f0b8f8e9e6 \ + --hash=sha256:3e5e1224c0a6a90e05843e07adfec669edebec17801c67072f51e59561d63c0b \ + --hash=sha256:41876ee62a3dddf48ff1121ad8f0798032aa03f2fd35f21f34a4cab14f18d8d2 \ + --hash=sha256:433c5a81eade63b47e522303bad236f59dba55ea6951746f5558355eeed8c75d \ + --hash=sha256:4582c27e8c889d64811987b5967fbd3ae0c823fe1fd933b543d55ac20bb475fa \ + --hash=sha256:485a0d363cafefcd2538a73c7c838daa2035f09b2c9f9b5e3133f80c6aeb84c2 \ + --hash=sha256:494b70049a4d69aec6e8137c13af4cf8db8c9f9820a1392ac293b0dd2987a818 \ + --hash=sha256:496846868fea80e479324862fa877f02411f2fd0f83b79ccee2607aa68b2a032 \ + --hash=sha256:4abdc5f9ad448c1ecbfae2974b820535d6bc6e7eef63babbab3d81cf46968c71 \ + --hash=sha256:4b599739b93b2cbeded49645ae3c8d1405c29ddfbceac1545c87a3f9580a9e96 \ + --hash=sha256:4bea7f8ebe90bbd7f0e4a2de42ca6924ba23e3e76418c408ff82f1d46fabd687 \ + --hash=sha256:4c4fb141a727957c93edfe5c32a26ceb6b5f6461d67146e2d39f51e16170bea8 \ + --hash=sha256:4c9548dc78002099910abaebc0a72ac58b7d30931869e0351c09b507dff4ece3 \ + --hash=sha256:4d26f14f041e83dd8edfd61f4cd4fa7285d31798b5bf1f28e70c367ba6c41d61 \ + --hash=sha256:4f298bdadb8f0b9e5672877f647d1be9373ef5320c9e2f049795e26cad28b6a9 \ + --hash=sha256:52ec005752a56ae79547a05c0139ca2501a0c866390b6115008456b9f0e7cde1 \ + --hash=sha256:55261ac0d2941c42f196dd576f543d87a8ee03cd6f5e30dfb4d807b2e3b9121a \ + --hash=sha256:56490c595a28b1bb27dfc583e816152a9767721ef58b2c03b13f954d2f707420 \ + --hash=sha256:58d3e12c88e0950bca850ae1f7c256055c097639c2edb9eb123af9807d8b15e4 \ + --hash=sha256:58d4aa13a59c969dbfdf9e6a9560e242cbfd9e8a8f50c2747714df1a423adf65 \ + --hash=sha256:59171c6e45bf07d0d5cab3b0bf81d945035530f6873398b3b531c31184d46663 \ + --hash=sha256:5b6d1386bf0096d26d3a863dc0a487a5b4eb9aa93cf5ba69683d29dde6b9d60f \ + --hash=sha256:5c0ea61a470e070686aa30892fed79e297d2c8d0ab46b8bcdf027d38c51da591 \ + --hash=sha256:5c84bec0ab5ae0c64bfe73a7d2adcb5ce73b467523fc27fd6a28ab2aa6cbe35a \ + --hash=sha256:5ca0555312ae2fe82715cada7fac375530c2f3349e1eaa1bcb33d0283ac79a18 \ + --hash=sha256:5d8531a6569d025f68e2321e7638fb7978f23db58e5f69f56913837aae03816e \ + --hash=sha256:5e2d0e146dcb57034f8b97dc58d2d512cb90aba253960ce449f695fec6a82c6f \ + --hash=sha256:5fc45d653ea8c9a20479167e11d4a0f8cb2fa3470737ab6f9c827532313187b7 \ + --hash=sha256:6117b84ea48435e5356dc737f5121485c30920ba43375fa7b434fd753df0eac3 \ + --hash=sha256:6199d5606e2bbf2b096cf64d03f8b6790c91081d5ac866b8e7bb6422738cc60c \ + --hash=sha256:62b55f6722735a6c472f88361cde6640608773d9443cebdbb51abf436a1fcdd3 \ + --hash=sha256:687c9ca3035544b113bea2055e180af96fb63c0c476e22a9180f51925186e7b7 \ + --hash=sha256:6b7430cf5728e68f6c462254009a6ef4086e1bea43cf2f57aa9c55fb4f50ff96 \ + --hash=sha256:6ba32c4d2abf1d2fe7cf27d280f4cca5664233b0f885549c7761719eb977f486 \ + --hash=sha256:6c9cdde8becb25a7fde49924511aa2644d6f8081cc8df8e9452724303348d8e3 \ + --hash=sha256:6df0ec430f9a831772c23ca5a224cba36517a58a84bb32c32bb59a9fa67c47f6 \ + --hash=sha256:6e2912d4babbc65196ac13c2f53468dc57fb8b9c25ef913e8c59ddf7c6dc0e1b \ + --hash=sha256:6e5e4d73d588ca5ed09df1b7dcd1b203d1df3c542e3f50d126c947d432b10731 \ + --hash=sha256:70055ff39b97c99e7ae40ea3e393fb62aa2e44dbd9b29f8d14f42fb0025c3959 \ + --hash=sha256:706bfd38730a5ac7a365793269a00f4e988178cec121391f4248d84ad8c972e9 \ + --hash=sha256:7235dc28fc6dd9d832ac7c7bce95367dedb85929f17368a0c2bee1e080b9acbf \ + --hash=sha256:774d157f112367ff4abd29019f38f023c24e00e56edc7829c20e358a5a913ad8 \ + --hash=sha256:77efcff2b23071c349402ac1066667a3d011f62398d81408c9b88ad991747c9e \ + --hash=sha256:789b8982559ae28dad2356519f841655756cdcd96616410590ae0b17454ee64f \ + --hash=sha256:7ac76cf9afd34929d76eb7fcb63be476a4853d8a96f0dcf2d0db68a0cbdf9885 \ + --hash=sha256:7c0c10730342b0c9b35dd1d619beb8214e520bd96a1f870f452680b238aab3e0 \ + --hash=sha256:823f82903d189af463d7df250ef1f7f696f3cee08cc8d91deb565e8d425f6506 \ + --hash=sha256:838648accb3a7fd9803fd45c87bce8509648eb0c11bc34e216141300977244f2 \ + --hash=sha256:854066be00447fa8de2ccbbe893e2ffc4b123ef16d897af794c1e18bd4a714b0 \ + --hash=sha256:85d5855daafc240cc045c026d7a15fd198a09b0fc8ff6f5ecbb5297b509cb11e \ + --hash=sha256:85de3134b5379856e323ba37c19c9256d39425f7b76a63af52b09fb4664c2e8f \ + --hash=sha256:87e4f41d375c0b9be2fb5251aee4b8a689169e134535aed81bf085c3b647451e \ + --hash=sha256:88ca277405c2d3b71c4e1c2ee0e7966e807bcba86a69d11e19ba199d18ae4491 \ + --hash=sha256:88e85ab89cb822c1e635f51d6d32e488f94e002e70e2f492bdb8b945543f345a \ + --hash=sha256:8ac8c94b6539074e0f40899301273ac8402b9b3e01c7b7ba269ff30340aaaf20 \ + --hash=sha256:8fe532b3c966d1fb794e0698e4589d0444017ae77fc0b31edea13c0e35bcc449 \ + --hash=sha256:9085f87b0e38a2b92b8923059b4e8789fe40d9279712d15dcc670048d77079af \ + --hash=sha256:90b7481fb62fbe172c558bc6fd1c4c98d82004a54a7551f20e11ac9bf0b8708c \ + --hash=sha256:92caef967d287a407085d61176fce4012b1dd62daed4eb6d5ceb26d3d2538712 \ + --hash=sha256:9362dd90aa7dab48c0054a21187791ccf05473f7dba5d92b8033ae62164675e7 \ + --hash=sha256:94d78ecec2605a8d0398b0f365d5f12a63248438516f5dac536a5eff7337df4a \ + --hash=sha256:94fbf1c0c6cc0d3d5e50f9a9313a8cdca90dd696d34b381cd1704f8c9e939f20 \ + --hash=sha256:950f23cb393f85543777b0433f082cddd25b51ab398eac7971146495679efe5f \ + --hash=sha256:96eefc178f8636b9c760c5829345307fd81cfae9ab1e80997dbddeb0f54ee9a3 \ + --hash=sha256:96fef3e886d6a9874b14f27fc193fbdc69d5d8035783d86aa4e1cea594e695f9 \ + --hash=sha256:977cdbd483a9cff38179bea4fd754289a6f2195c7abd414aba85410b3e66cc5e \ + --hash=sha256:978eab16f55b4ab2c2a745be9a0a840bf8f09a7f227d9c76eb30214d078865a5 \ + --hash=sha256:994e883d17c559cdfd38c84003c8b27d25424a1077272a17e7cd27bfe0bf57b2 \ + --hash=sha256:9ac4444d8d4fd4c4bd08bf451ed3167aa9e7ec6cdb41b648794f1d1103652e36 \ + --hash=sha256:9b5db6052055d34d41230fb78d7c439c23dc536a9896f6cb039e8dd92cfc1263 \ + --hash=sha256:9d9a0dc7cbe9bec24c3f767c9122c41fe5a1bc43f47cd099d00d393e09769de4 \ + --hash=sha256:9dbdd9205662134957cf0c324f639bdc5031c0ca056e2369e238db75187c0f11 \ + --hash=sha256:9eea3ab2597a5e65fe65296e2d6a84570845a6b55532d90333d740d48bbc850a \ + --hash=sha256:a2028475ba855475b8b4d3cfeb4994269c967aea8b9892dfba907f4263a863a3 \ + --hash=sha256:a3a370082ce34d0612f421e15fe011c53bb1feff21a26d06ad4fb244dab5a375 \ + --hash=sha256:a545775cfe815855ea32d7c27731d79da358ef2055b4a25830231b1622dd18aa \ + --hash=sha256:a5cbd90ecf0fc62e64726917ad083b73001f0563657a87ec3c0b504e277dc90d \ + --hash=sha256:a6d095662e73e74f0a49988e0593373e243e3a52e27bfeea0a859e88acf4a0f5 \ + --hash=sha256:a6dac12ff6b846103483683f60c5f8fee205121adc58ffd87e90a90a3af69e99 \ + --hash=sha256:a951ad59cad9145664a730d3036b40b844e74d2d3683da40111463cd3a83845d \ + --hash=sha256:aa1099b956fb795e686d073568f6dc002a0bb89765ea6d5b055dd7d9bf1b116c \ + --hash=sha256:aa2bb0b37202dca27175591f761108b5d34096ade1191ffe4808bdf6b1571488 \ + --hash=sha256:aae2ee51122d3ae968a3837d97dc24a0aeebb0dea23694422cd172bd30017cd6 \ + --hash=sha256:ab743e9bc90c1f73552ec33e10e3331315acd2c397b36065b591b0181de533cc \ + --hash=sha256:ac00177c4831ffa650f8609e4bdddd5fe09c03b1c0c47acece7e6ea20421598b \ + --hash=sha256:ac13b004224fb341e1e25a1ed5e19d32f57cdb2a403e01f003b46f051a550f6f \ + --hash=sha256:acaf604462bf330b0d07e7a07c1d6e4adac79e5fb13e9c5140590542cafacc00 \ + --hash=sha256:ae31a1a1db2ee6cc2942fccaf695c934bc7f3db9f2133a3fef1f367cf1a4ab10 \ + --hash=sha256:ae4a097991662cd4fff0ddc74e0fe7874f82e00042fa0ea00855645ed0c79598 \ + --hash=sha256:aea996a6aba25260827c9ea511d1addfde2da9eb686ac961838509086188b7e6 \ + --hash=sha256:b39b69b347e5e47a3b5b8cfc005c68c1ba347474e3960236c4944a8ecd174962 \ + --hash=sha256:b54e7e13267d49ffbfe68e25b3cbd774dab38fa37238f71265e91b36146eb21c \ + --hash=sha256:b9af956078716df40d985fb0dfeb2c2120c5ca92ba4ff4b388acfd01cdc14d08 \ + --hash=sha256:ba2f37ee79e6338845261a3c5b1784e5d1acdff2c0785b284f1b633033d136ab \ + --hash=sha256:ba501e667c17d8411f98e67a022d9604ef179aff0e459b7e292c796837c13573 \ + --hash=sha256:baf3775a2635e5a11fbd5e4e64ee69c7e86875d224a5c72aca4c141064589a90 \ + --hash=sha256:bb57753e36e4855b8ca375069482250a6246372331a3e4f3407eaebb007443f5 \ + --hash=sha256:bd6c173f04743d483881bffa1478d5a4624475b8cd1d2194956a75548e191c18 \ + --hash=sha256:be47f99644b208bff7766314013f9acf57b056b04191d570d68ad14022cf5b1d \ + --hash=sha256:c010f5581d9c612804cc59fcf7b524b707fbcb72828551237ab545bb5c7034af \ + --hash=sha256:c1dcc36dcb96abc02236e182d17e0f71430152a6c2c7447421da2d2dc144edea \ + --hash=sha256:c428c6c31eb5f4277d7f8eccaf767fbd548ddd5ce3c8b4f4cbbfab3d96b5904c \ + --hash=sha256:c658c50ac0c98cd755a2dd50b7977d3bca7df401dcc47fbdfa87db53ef7d4e8b \ + --hash=sha256:c71fb0d56c920c269cd3e2e3fe7c610e3f1fdb21a6ce60efa6430ff63676cea6 \ + --hash=sha256:c7b742bf31c88566b4bb6335a7f393bb322e580b6bb98df7bd0c25e6e3519ce8 \ + --hash=sha256:cc0329df4caaceb950d2f580b5ac716a377f7059624a0bafaeaf8a218c6ed774 \ + --hash=sha256:cc5d36d96478aa9c60654bd932525bf32964c62a7281eafdf16d85003a8d6004 \ + --hash=sha256:ce854f5f478050ade5a238731c4ca985a7d3b3cb53ff600a9b5c3b689b5f0a7a \ + --hash=sha256:ced3fdd71aaa83ce593746c2edb42b7a59cb4c19c8b5c407781c72e493aae55a \ + --hash=sha256:cee5dd7c6fb5dd52a0fe2a740f9bc6e3593f5f8b1788bde49de02086f30182b2 \ + --hash=sha256:cfa1c0cc3a8f9f53f1243a5a99ac36fd003880199383b37672e86ddda9cb07e2 \ + --hash=sha256:d1ee1e296209fdce05b81b663250eefa02213a2da7b41bf26f7829b8ba3545aa \ + --hash=sha256:d59b75732e9b6f27388e10c14b0259cc5f2e48c78627d185e6a177b58ad3cffe \ + --hash=sha256:d63600d620ad0064c3a748b950ac5ea38a80190e5498532efefa4b7b3f1da1f3 \ + --hash=sha256:dd732602a7009217f658d5863d12d79d373a4de0eebc111094bcdd3bb8e0a6cc \ + --hash=sha256:e06efa066f7dbadbc84ebc126a97c452a6451dfcf589d89d788484949e1cf795 \ + --hash=sha256:e199fb99720074809a7720f1c0b4d919eea8b87e88713e0f8f602f7bef543d9d \ + --hash=sha256:e4b018dc5a0eee4676e38fe84a47a427816c590b93b55d9025274ec4d6ffc2dc \ + --hash=sha256:e6621fb2a4988d6e53eedc455e5903e2679f3967b8acb3d639f1b63c14a2e893 \ + --hash=sha256:e71c909f353863b2b89c83de2ebed71ea6d0df8a6ef65a128193c5e650766bef \ + --hash=sha256:e90251c0c7bdd54a100a0dce3c07b7e637278c93af29dbf78ebb89a58c4bac7d \ + --hash=sha256:e9fbdce1e47394b09bc9f26ab117dfc8d6491977a11d86f592bb42c779db2fda \ + --hash=sha256:eb12fb2ba69ffa05f8695f61c69e591dc4b4a12ac3757ac8af8adb259bf56d17 \ + --hash=sha256:eda059b6bc8bc0812d626fd91a7ce01bf583df0a61296eff390fd94141a34e30 \ + --hash=sha256:f03ac127268b43ef4fe9e6ab6794a6794b49485a0cc0c1db79876d2f33f75bc7 \ + --hash=sha256:f298e218441525d3794428b4c8b8fb8662c6d3ea79925d4807ee6b9a96a3bca5 \ + --hash=sha256:f5542f9b941279d82d41eb0aa9f98eba36fe4df5c7086c651df7944935b37182 \ + --hash=sha256:f6f7deae3feb4edfa2efaf7c574fe88cbf055038a6abdb40188e4fff66d5699f \ + --hash=sha256:f9b1e28d0e8dbfa858abdba91d6b547beaf2df1a59bec6da6faae7b96a4991a9 \ + --hash=sha256:f9f8405c2c758532c74fed975dbee57be1f31a6e865c031870c79a6ed3212ada \ + --hash=sha256:fa48b1b63d639f9483e0633e092f5851e2348c352f1f9bb6c8182f87884ef876 \ + --hash=sha256:fb78f6e7fcd8ad785d28cd577168bc1aaee827b25bb8755638f694794ea98f0a \ + --hash=sha256:fbc597639158fd7c14d55e808718848319540f51b0e6746e3eefa59723a4a348 \ + --hash=sha256:fce8cbd4997efeb450bd298b54f755dcdff18d496f7a5ddbb4867c6d7c88fdc3 \ + --hash=sha256:fd0350afdc3aabd5576f60ea109228bd5538139713c7b094c5cd27c73a98bc6f \ + --hash=sha256:fd0a274c0e5f9a21565cd9d3dd749b61f96b7aa1e20a93aa1ba4029518f2e5c0 \ + --hash=sha256:fdb8a068947befafba9952162645dc2fecaeb400e64584829ed5e9b2fbe21a7f + # via requests +click==8.4.2 \ + --hash=sha256:9a6cea6e60b17ebe0a44c5cc636d94f09bd66142c1cd7d8b4cd731c4917a15f6 \ + --hash=sha256:e6f9f66136c816745b9d65817da91d61d957fb16e02e4dcd0552553c5a197b76 + # via + # click-option-group + # semgrep + # uvicorn +click-option-group==0.5.9 \ + --hash=sha256:ad2599248bd373e2e19bec5407967c3eec1d0d4fc4a5e77b08a0481e75991080 \ + --hash=sha256:f94ed2bc4cf69052e0f29592bd1e771a1789bd7bfc482dd0bc482134aff95823 + # via semgrep +colorama==0.4.6 \ + --hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \ + --hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6 + # via semgrep +cryptography==50.0.1 \ + --hash=sha256:01f41478cf33fc605a6a089cd56d28b45c6c0b45a1928b61797f2621a04bac71 \ + --hash=sha256:05ba322c4da95b262a212c345af888ef2c37c88c0509756ea00a0e6d68850f23 \ + --hash=sha256:16c5ecd954b3330ebfb6605eca4fd952da8bef376551d5cc264534e3770a9ee6 \ + --hash=sha256:2a93d05e34d5f67fba6f891fe85d929999baa7195e853923ea6d7576c9e68c5e \ + --hash=sha256:2b34d76a652ea2b6faf777c35df230c5637842cd904e04f16230c3f9f03e4361 \ + --hash=sha256:2ebbfb0f1fed745e91796e3e1080a1440423fdae8ece1b995a1d80883a409054 \ + --hash=sha256:30a125032e5642a21ff816e021152bd4e7e94f03eff3f4b7fca41cd22bc3110f \ + --hash=sha256:330fbb252391c596f1ae42c5754449dc924e6ad012dca8efe0d703f9f2d12ec6 \ + --hash=sha256:359e62deae718bce96170e223fdcb6357e4fbd3bb7a3a75f4430763532560e49 \ + --hash=sha256:407fe2b6db00939c05c0e945e9914238f2f0a430974839429dafc82b1ee6bee5 \ + --hash=sha256:42be3bb70596b3abe4ac097b75be223e8b3ab614a0e5de068e3dcc54d71d6149 \ + --hash=sha256:4c4188f7c0cf655be5c06342b817ed0f9595b69ffa2b12026e5353eed29dea88 \ + --hash=sha256:51593d180cf6d179bde5c5d065bed81386b1f381656ae7d042b7ffc87a9895ad \ + --hash=sha256:51afcfceb15597cf2635068e4ac9a56b2abde622edde17f37d85fd7b5306497a \ + --hash=sha256:53e279950892dc102c6b4e52af03ae5ea92fac572a1ddab78ca73a997f62b69f \ + --hash=sha256:55d16b1ef3ee0958d893a977b19777887e546c9954ea81b200c3301a864013f2 \ + --hash=sha256:5dd9bda1c12b4162f6ff568eeb5e0ff956c28d14406e875cfe8a63a2d414ff20 \ + --hash=sha256:5fe002589592ed749ce77fe0695fcbd3500dd61d7d6db5858a7544c612fa8e45 \ + --hash=sha256:5fe939deeb161024a6be98229c953b6591fef1f41214497a78fe793a244c017f \ + --hash=sha256:693c99b49bd37d0d096e4334c10232c77248c415b98d35236094cdf96d57258b \ + --hash=sha256:76de83fbd91ac49c0feaaa983d0748fd7a53176afac5fb3bf7478d244f0eb527 \ + --hash=sha256:79bf008d1f9af6071c797ad133e39915dfee7614f18f18f4db9072eb715064a3 \ + --hash=sha256:804728ce710890870f3aaa344b2e161172d258d768ac139d02cfd9092d0d94e6 \ + --hash=sha256:8921d58f426793c5f1b47f0b59575780de9a095214958d0eb37d909593db8367 \ + --hash=sha256:8df2de9102026855887e4587084f6eabd80ed0f345b8ad8a7ac27ab9bf4723e0 \ + --hash=sha256:9cb3cb952cf5a8abd50c782a98a89d71699715e802fe349704b47f2425b42a94 \ + --hash=sha256:9dde0a357190eb3b1da1bb9ab750e9c85cba82ca5977aa0836cbb94e92611239 \ + --hash=sha256:9ebcdd5519be9b652a46f507817a74591774fc3d6923ac364e4dfa64e36b291b \ + --hash=sha256:a0b1a59e3a089064a0ec309e9428c8e3ae4e161419d20ac33600767e83fc658a \ + --hash=sha256:a255449073358275b64b67d3f595f268bbef70e72b6edb65e0c70c735bf739c9 \ + --hash=sha256:a8f40ea47330e71b594a7e246898f93177c259490c63183dbaf9e571d71ed9a5 \ + --hash=sha256:ac02b07824d4d1001bd4367599f839c19cb171924c796e52c23508ac14c2c0cc \ + --hash=sha256:aed8db4f6d71c51efb89530e12d9464e7bf2923d46c3205dc794a2a93f8c0648 \ + --hash=sha256:b8f852c65863251b9e3a1b8c150ce21e59b522dbb6a7d4bc80e680d38388e986 \ + --hash=sha256:be224a65493ec5b74a158ff22a5522ce4a5ca1e543c647a3a4730d4a09e5f959 \ + --hash=sha256:ca83d00d9e69cd5eb63f2e69c3a5a59e0cecae5ae14c6ae0b35830fe3b37bad0 \ + --hash=sha256:cbf74a81765ee67413503ca6e26dcc4f6f5a519822436cc0a1b97aab6c1b8a17 \ + --hash=sha256:d63ae8f6481fec907ac0f588eee8a90aefde112c633131fe540e5711ddbb5a4e \ + --hash=sha256:e22dfed744bd4002e909464cb23d2f0b05c6f3113a79ef2e9864a53db737c733 \ + --hash=sha256:e2ca8fd1b6b4b82a1c4cb02841d0837e3c12336c2e24b520ab8ab3b969733d8f \ + --hash=sha256:e74591e283fe6eb956416c929eb58262a719fe0311fd9054c62c3350ed8760d8 \ + --hash=sha256:f74455bb086a85d5e81246412602aaa97ed095e504cd40dd261ef50be42205bf \ + --hash=sha256:fb4b9672d389c738b175c4166e78310f8a70358886aacd9173ee03a85ffdc671 \ + --hash=sha256:fc3ed7ebd2a8c96f5b166de0ab9b624996bef3b07bbeb19364dfb78222c22c80 \ + --hash=sha256:fd3718b960d0b5dd213cdf03f3bcb7000e69dda0de8b956061947ff6bcff5558 \ + --hash=sha256:ff838d62ec1bfce4f9ba7fa16f4a7b554cd8d0c299e6be37502161a660c84eef + # via pyjwt +exceptiongroup==1.2.2 \ + --hash=sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b \ + --hash=sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc + # via semgrep +face==26.0.1 \ + --hash=sha256:8183d94bc248baaea855a9f8445f97a22a9988908e60abddccc6e251da77c4c6 \ + --hash=sha256:ab0a83c37c9789dce658a67a9a80eafaa113c9ec37c5a9d950ff5480542a062d + # via glom +glom==25.12.0 \ + --hash=sha256:1ae7da88be3693df40ad27bdf57a765a55c075c86c971bcddd67927403eb0069 \ + --hash=sha256:b9f21e77f71a6576a43864e85066b8cc3f0f778d0d50961563f8981377a6dcb1 + # via semgrep +googleapis-common-protos==1.75.3 \ + --hash=sha256:57c435ac2c68b108999b6db075d9053e4d7a936ba57b4a3d45667b1346f1738a \ + --hash=sha256:a018d2bf098ca9fb6faa08d5bb780e2a2c2f73c566f069761331386c9596d3f2 + # via opentelemetry-exporter-otlp-proto-http +h11==0.16.0 \ + --hash=sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1 \ + --hash=sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86 + # via + # httpcore + # uvicorn +httpcore==1.0.9 \ + --hash=sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55 \ + --hash=sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8 + # via httpx +httpx==0.28.1 \ + --hash=sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc \ + --hash=sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad + # via mcp +httpx-sse==0.4.3 \ + --hash=sha256:0ac1c9fe3c0afad2e0ebb25a934a59f4c7823b60792691f779fad2c5568830fc \ + --hash=sha256:9b1ed0127459a66014aec3c56bebd93da3c1bc8bb6618c8082039a44889a755d + # via mcp +idna==3.19 \ + --hash=sha256:5e0811a4383b21dc5838069f801c4fb62113b7447663d2530d2bd6e77b49bf15 \ + --hash=sha256:815e7be7a7806d54abb586dc943addc79e8b2ee16915059658cbeff4b1b43bf4 + # via + # anyio + # httpx + # requests +importlib-metadata==8.7.1 \ + --hash=sha256:49fef1ae6440c182052f407c8d34a68f72efc36db9ca90dc0113398f2fdde8bb \ + --hash=sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151 + # via opentelemetry-api +jsonschema==4.25.1 \ + --hash=sha256:3fba0169e345c7175110351d456342c364814cfcf3b964ba4587f22915230a63 \ + --hash=sha256:e4a9655ce0da0c0b67a085847e00a3a51449e1157f4f75e9fb5aa545e122eb85 + # via + # mcp + # semgrep +jsonschema-specifications==2025.9.1 \ + --hash=sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe \ + --hash=sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d + # via jsonschema +markdown-it-py==4.2.0 \ + --hash=sha256:04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49 \ + --hash=sha256:9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a + # via rich +mcp==1.29.0 \ + --hash=sha256:52d01f334de1868cc3bb2d6604931126a67631f99a6c5d3b82ba47290315ec36 \ + --hash=sha256:f5a075bb611f23d6f4d080c6a1699fa62772eebc562ba9e66b306ddde1c755f7 + # via semgrep +mdurl==0.1.2 \ + --hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \ + --hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba + # via markdown-it-py +opentelemetry-api==1.37.0 \ + --hash=sha256:540735b120355bd5112738ea53621f8d5edb35ebcd6fe21ada3ab1c61d1cd9a7 \ + --hash=sha256:accf2024d3e89faec14302213bc39550ec0f4095d1cf5ca688e1bfb1c8612f47 + # via + # opentelemetry-exporter-otlp-proto-http + # opentelemetry-instrumentation + # opentelemetry-instrumentation-requests + # opentelemetry-instrumentation-threading + # opentelemetry-sdk + # opentelemetry-semantic-conventions + # semgrep +opentelemetry-exporter-otlp-proto-common==1.37.0 \ + --hash=sha256:53038428449c559b0c564b8d718df3314da387109c4d36bd1b94c9a641b0292e \ + --hash=sha256:c87a1bdd9f41fdc408d9cc9367bb53f8d2602829659f2b90be9f9d79d0bfe62c + # via opentelemetry-exporter-otlp-proto-http +opentelemetry-exporter-otlp-proto-http==1.37.0 \ + --hash=sha256:54c42b39945a6cc9d9a2a33decb876eabb9547e0dcb49df090122773447f1aef \ + --hash=sha256:e52e8600f1720d6de298419a802108a8f5afa63c96809ff83becb03f874e44ac + # via semgrep +opentelemetry-instrumentation==0.58b0 \ + --hash=sha256:50f97ac03100676c9f7fc28197f8240c7290ca1baa12da8bfbb9a1de4f34cc45 \ + --hash=sha256:df640f3ac715a3e05af145c18f527f4422c6ab6c467e40bd24d2ad75a00cb705 + # via + # opentelemetry-instrumentation-requests + # opentelemetry-instrumentation-threading +opentelemetry-instrumentation-requests==0.58b0 \ + --hash=sha256:672a0be0bb5b52bea0c11820b35e27edcf4cd22d34abe4afc59a92a80519f8a8 \ + --hash=sha256:ae9495e6ff64e27bdb839fce91dbb4be56e325139828e8005f875baf41951a2e + # via semgrep +opentelemetry-instrumentation-threading==0.58b0 \ + --hash=sha256:eacc072881006aceb5b9b6831bcdce718c67ef6f31ac0b32bd6a23a94d979b4a \ + --hash=sha256:f68c61f77841f9ff6270176f4d496c10addbceacd782af434d705f83e4504862 + # via semgrep +opentelemetry-proto==1.37.0 \ + --hash=sha256:30f5c494faf66f77faeaefa35ed4443c5edb3b0aa46dad073ed7210e1a789538 \ + --hash=sha256:8ed8c066ae8828bbf0c39229979bdf583a126981142378a9cbe9d6fd5701c6e2 + # via + # opentelemetry-exporter-otlp-proto-common + # opentelemetry-exporter-otlp-proto-http +opentelemetry-sdk==1.37.0 \ + --hash=sha256:8f3c3c22063e52475c5dbced7209495c2c16723d016d39287dfc215d1771257c \ + --hash=sha256:cc8e089c10953ded765b5ab5669b198bbe0af1b3f89f1007d19acd32dc46dda5 + # via + # opentelemetry-exporter-otlp-proto-http + # semgrep +opentelemetry-semantic-conventions==0.58b0 \ + --hash=sha256:5564905ab1458b96684db1340232729fce3b5375a06e140e8904c78e4f815b28 \ + --hash=sha256:6bd46f51264279c433755767bb44ad00f1c9e2367e1b42af563372c5a6fa0c25 + # via + # opentelemetry-instrumentation + # opentelemetry-instrumentation-requests + # opentelemetry-sdk +opentelemetry-util-http==0.58b0 \ + --hash=sha256:6c6b86762ed43025fbd593dc5f700ba0aa3e09711aedc36fd48a13b23d8cb1e7 \ + --hash=sha256:de0154896c3472c6599311c83e0ecee856c4da1b17808d39fdc5cce5312e4d89 + # via opentelemetry-instrumentation-requests +packaging==26.3 \ + --hash=sha256:94edc256424af38762eb31306eed28beb9f0efc50a8837492c9d6fd6004aed79 \ + --hash=sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c + # via + # opentelemetry-instrumentation + # semgrep +peewee==3.19.0 \ + --hash=sha256:de220b94766e6008c466e00ce4ba5299b9a832117d9eb36d45d0062f3cfd7417 \ + --hash=sha256:f88292a6f0d7b906cb26bca9c8599b8f4d8920ebd36124400d0cbaaaf915511f + # via semgrep +protobuf==6.33.6 \ + --hash=sha256:0cd27b587afca21b7cfa59a74dcbd48a50f0a6400cfb59391340ad729d91d326 \ + --hash=sha256:77179e006c476e69bf8e8ce866640091ec42e1beb80b213c3900006ecfba6901 \ + --hash=sha256:7d29d9b65f8afef196f8334e80d6bc1d5d4adedb449971fefd3723824e6e77d3 \ + --hash=sha256:9720e6961b251bde64edfdab7d500725a2af5280f3f4c87e57c0208376aa8c3a \ + --hash=sha256:a6768d25248312c297558af96a9f9c929e8c4cee0659cb07e780731095f38135 \ + --hash=sha256:bd56799fb262994b2c2faa1799693c95cc2e22c62f56fb43af311cae45d26f0e \ + --hash=sha256:c96c37eec15086b79762ed265d59ab204dabc53056e3443e702d2681f4b39ce3 \ + --hash=sha256:e2afbae9b8e1825e3529f88d514754e094278bb95eadc0e199751cdd9a2e82a2 \ + --hash=sha256:e9db7e292e0ab79dd108d7f1a94fe31601ce1ee3f7b79e0692043423020b0593 \ + --hash=sha256:f443a394af5ed23672bc6c486be138628fbe5c651ccbc536873d7da23d1868cf + # via + # googleapis-common-protos + # opentelemetry-proto +pycparser==3.0 \ + --hash=sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29 \ + --hash=sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992 + # via cffi +pydantic==2.13.5 \ + --hash=sha256:346a034f080da3755d8e9cb5e00e8b07de1d39e4f6e2c87d8ab7cafa0b269a73 \ + --hash=sha256:51a9c5f7b2f8e636f04c6cada605d9b6a3bf1348fdf945a3d8869b19bba0ee08 + # via + # mcp + # pydantic-settings +pydantic-core==2.46.5 \ + --hash=sha256:013d6f3483d81e02e7c328831808f336c8596ee33b4bd4026b9ffb1e960b8942 \ + --hash=sha256:03b9666e41e35d8909852ba191a0607520f81b74eaf12ccf8737005dbb313821 \ + --hash=sha256:045ab3b6d308439e32b81cc173bba5b9018bc6ed896afd0c65b3b009b1699af5 \ + --hash=sha256:0bddb4020d8f04175865ccd17eff3040874fc11fb593f424edb452653b4b947c \ + --hash=sha256:0cdbada856a1c69a7624a64d3d9aefe79300bd6ef827b43a4f265010b9b55184 \ + --hash=sha256:0fc5be0abd4a407e200d844b404e33639a554e7bd0d448e7b9ae181be4789ac2 \ + --hash=sha256:10416c15b8839ecc4ef4d0885da76da6fd0f67333a0eb8aff6d93c4b8f2910fc \ + --hash=sha256:15f4a94963c95accac15b7b657bb177d3ad82bb90b0d0526d9a9b85079925db5 \ + --hash=sha256:18a09e1e1011b462f2e32774f25859ef1223d5c2b0546a633cf56654710721e0 \ + --hash=sha256:193375f3548919d3f0b60936ca113ada3e38f264f91b9b8e0508efaad57be931 \ + --hash=sha256:1a353f84de772f423b5ffb11d7ae352fbbef0f446f3c0b0af0f8236d7233606e \ + --hash=sha256:1e449def1945a462c464331254e5a44fca7c3b4f9aedf59ec2f50f8066dd8e25 \ + --hash=sha256:1e5aad1220a1192c42341c8fd4a8686657e73ab2a920c970bdc4de334fe3193d \ + --hash=sha256:200aa3dc9f8d54f0754f43247c0bad0999fdcfbfd2488384dd44f37279271fe6 \ + --hash=sha256:2471fd51c61c610e1dcf7de44d7299283661654d11264ab4802b303368d69c47 \ + --hash=sha256:24922243639cbdac66c75fcb6fd6495a9cb52b213d62f9a0d16f0310b1ff8038 \ + --hash=sha256:28a6a556cd3b6066bea827857f9d9cce027c96f776e512f544a581f9e42161f8 \ + --hash=sha256:2bc9419666990c06d7397831f2126a1ecc3594aaa3ff7de5bf2d066802f4e07b \ + --hash=sha256:2cbd9a5eff05e51c447c34dfa4632145b26b09120cf04bd0c871e44c1a5e1c9a \ + --hash=sha256:2d330aaba8621b1edcec8ae2c4050f63b84ccf6d98723a8f212e9684713abf0e \ + --hash=sha256:2d5d76654becf5efd62c9e51c3756c67b49498b0c9a40884934c40807adbd074 \ + --hash=sha256:337639ba62a11acde6ef3aeb08c8ea755f8ef1fe5e513356c0f36a2b0d7568b0 \ + --hash=sha256:347ec774390c87326a2e4929d58d3f7e8763a104d5d35f4cd595a4c952366433 \ + --hash=sha256:356c8368cbc321050b169595683a2e1d63413b1e0e2868b330af9fc14c616d3f \ + --hash=sha256:37ae34309d7bd8c0d61ab839668058f2a7962ea1fc51d105d2db228fe0618034 \ + --hash=sha256:37ea7b83c935e5b0d68c9449b82651accf78a10828b2c02b2f2d9e9496446c21 \ + --hash=sha256:3a3e26b6a8274211bddee2d0e4d0d42778f17a34510f49d2ec44b58abfc41736 \ + --hash=sha256:3aa166e99c4f2985407fb8714aebede877ecb5455cf321b606adca926d30d5a0 \ + --hash=sha256:3d2652072b2d774947ba5cf78a9e59644ac62ee572daf6dd2e1dfe905e15b2b7 \ + --hash=sha256:40375c2d05acec10323e45dfe2077ac44bc74659008614af5069034e2cfc781c \ + --hash=sha256:413a717a410d0c817ef5b786a059415550b3794e1d0c2abffd9efb93a3d9f7b4 \ + --hash=sha256:46c25dda9d092a06c08db76ffe0a197107904d0dfac653f7d5306bbcd6d6119c \ + --hash=sha256:49776eab08766a08dfff7012f8b422dcd7e25e43b316eedf0477c24fcfa84b7c \ + --hash=sha256:4d44cf99ddebf875f9b68cc267aa684c99b7b44fe63ee1cac4ec163807290069 \ + --hash=sha256:4dedce55295becb61921e386b99d4f2706045306e7fa52249a33004c837379fb \ + --hash=sha256:4f8507560a9284e1370bb048ed4282012fbef4e8d109875b95e884d228552061 \ + --hash=sha256:4fdc8b93a41521988916eeaa271173fcca7fa0803d62f87675aac8dcec1c8e29 \ + --hash=sha256:5086029a57366b8cf81b130a43908738095c270c21a8d7f0e8bdfdb89718e2f3 \ + --hash=sha256:52e24eacdb536cade636aa90fb851835222becff8484b7001fdc78cb0290f2aa \ + --hash=sha256:53feb344243bb9510a9dec7bf3cf1b64d88a98af5dc7872a5160465f8b198c8e \ + --hash=sha256:545f26c504b27c3758439a5e6d9349931f0a04f855668d5fe323c89e82300a38 \ + --hash=sha256:54d510bac3ee52247af28ed4bb18a1e799f040ac60fd2bf5ccd4c92f1fbe786f \ + --hash=sha256:5cb482e9e84c851f4e623fe4acc1ced89168cf1fe18f7089db4548c8f5bbb65b \ + --hash=sha256:5e81740c09e310f5aa5cbd3e434a01c154d4bef93241c7877b39f211d2b78ba8 \ + --hash=sha256:5ee239d575f80b08eca11f6e20f90c4c695de7825c67eefe6091fbf20dda648e \ + --hash=sha256:5f194189415698233dd1114a093a9b56e61e2c57e11b469be3b0506f46f0771c \ + --hash=sha256:5f93c5fe914d75fbec9a49209b00da5f08e9e467d69da2b1510c81940cfd10be \ + --hash=sha256:657b40d6240c0a7b6a64b30f22d1e3aa631c7e846c621b0c0f6d1d75e2e15ea6 \ + --hash=sha256:6d30e1a4f138b8951063e9a394752a9179b51da288ffa507b1e659222f4c1793 \ + --hash=sha256:6f7b393a8b3da82f5c1fc0751e6d01ac6c55b93c18226a60bdfba4a724efafd1 \ + --hash=sha256:701b2e04b560eeb4bddf7a25ab8ca476176e34fdbd9a0e18196f0d12d4685f0b \ + --hash=sha256:771cf63ae0b1b50dd22e5f3e3549fab5f3f4ff1635d352a9e1a97fe01c7b2e64 \ + --hash=sha256:79bdfa52f843137045b2d081cc05c120ba6665d29b7559c2c47690906f39279f \ + --hash=sha256:7ac031912d54f3d83ef3b3eb98dfabc1608802e2202263d25957eeed40b94761 \ + --hash=sha256:7b0fc826b16c55e561e5d2a0c5c77b051ba1d92808118c4e4b5390f5e0cf191d \ + --hash=sha256:7c6be839a5a8312626b32029a415644a0846b420bc8b52b95b28cd92da162168 \ + --hash=sha256:816ff0a6550ffc06c098ccd2e0698600f9aa7da192a79eaa6f9af504a35db869 \ + --hash=sha256:82a36973cf8a2ef5406f4fe2edbf8ed0c99629535d959e0b100c76a32535a111 \ + --hash=sha256:837b396ca3d7b74091ca623f6cbd8351bd42d670a79c2683e79fb089f06a2de5 \ + --hash=sha256:850a08d167dde16db8702c274f320c7be9d7da6f6dff2b58b18f9e815bd94f5b \ + --hash=sha256:8816f3d218beb4b787de5c9759c259b8fa61f9dec42dc7811f320a33771778b7 \ + --hash=sha256:892a881d5f68c2b9ea304b7a6c2c60d9343df578a311b0f86b94bc8f1ffe8129 \ + --hash=sha256:895395f8918627b04efb1ad2a4cf605387143300ba03304cd1dfa6d03f5e095e \ + --hash=sha256:8b10e3e8fd7ddc2bd915848a2768e44c15b22936f1cc54c462ad1164deb02655 \ + --hash=sha256:8e24d8f05fa2d28513d94e877e9c75ad66175376209b3977f916e240e623193c \ + --hash=sha256:8feeac04b5794e513e710af2f9c87d49f31a6dc47967bb264a1fed61a8989bec \ + --hash=sha256:9432f3598db432cb51c5b37fdbf29a60fcccc79e30d37a05022776a6bc4ab689 \ + --hash=sha256:976e1128455aa595ea04c79ccfedff1aaeab96ee013fcc916bed120c4f0ad94f \ + --hash=sha256:978e7b97d4824b5be09c69fb70507cbde3b0323fc147332ca40a94d9a6a0ebbf \ + --hash=sha256:97bf8de4d541598c94a59344eeb988a94c08ff76b5723c41f6567ec18c7892ea \ + --hash=sha256:97cf3eb53a8cccacf9d46686a0926186c9bfb5574f2ed66d3639d5fe117cd3a9 \ + --hash=sha256:9b68938dd5b0c783d88ff8e2dcc69451b5eb936fe212d516b21b9d5567f6d464 \ + --hash=sha256:9c4b71f10dd532fb7a5cbc8f58707779e64f03a258c2bf8bfbaecfcd9970b519 \ + --hash=sha256:9f47b8a949e60f027f0aa0a6f6c7b7e9c55cbf4380d10b344e282fa4e7ab1e1b \ + --hash=sha256:a1dee1b804ff4d11c663636cf15d2ea47e9f79cd56c033fb1cbf08924842a48f \ + --hash=sha256:a2468d93d181667a7abd66e1b64bb9f76f361b0fef8faddf687456453576f5ee \ + --hash=sha256:a2a5e1d0ff29adddc9f6d6821a66302e4493f8ca898b715b6b1182c2c201ea0a \ + --hash=sha256:a39ac25a9a2fa4072efdb429833c4a4c8009a51ff9eea3eeae131713cd27991e \ + --hash=sha256:a445486499897b88a7d6c310c88ed64dd37b1b59bfd7ae9107490bbb362f47d6 \ + --hash=sha256:a91c17edf6eea2402cb5457b4c89e99bc5ed1004aa34c4adf1d4258c1a5c22c2 \ + --hash=sha256:ab4b66edffb32d9e951efb3814bd104b8367a7501b81b955cacb5726d897389f \ + --hash=sha256:aca6c767f552b21b10f774aeac128e828eafb796adfa1b666a18bf6321453c3a \ + --hash=sha256:acf8a67ba51f4ca9ddbd0e6b3000a65ac51ab734661778b3e7ba64d99a710f2f \ + --hash=sha256:b10ec717381bdbfafef34607824db4c91de69ff085e4fca3b2af91b4fa17e68a \ + --hash=sha256:b49924c73a235e969511bf2aabdff3beebf9820931f646c80274d5d780010c47 \ + --hash=sha256:b6acfb46a814762367fb7ba0828b0a17d441b92ce249a0e007474c9072662dda \ + --hash=sha256:b7ca9034437b6022f941f4857459562ee00a560b97e7cce8a0ec5a74fc6766e0 \ + --hash=sha256:b98134087d9de723658d17a42c7d0da8d6e2ef08015dee7dc93889047315f5e4 \ + --hash=sha256:b9fe6fb92520e3fd61f2e49000b6911b188824f089b75973ea06d6267f0b476d \ + --hash=sha256:bce57638e08ac148e5778cce7feb968307a727d66f8e2274a543d0cf0c9ad6a3 \ + --hash=sha256:c14ad3bdc85ee7f318742c457ca3968a92126d144b15721c759033bfb06296c2 \ + --hash=sha256:c1c43ad4339643d70ebb8124e1305a7dab423001eff58bb41a0f731adbc98355 \ + --hash=sha256:c3471e5c4a949c26ec00a77f01df59096aa9495877de76fd60a980f8ee6be461 \ + --hash=sha256:c583b927a8838dab890706a6fa7573fbb8b70e24000ef9f7238e2d6f6435a5ed \ + --hash=sha256:c76fe65e607be28c7fd4d56fc3c42b1583aa058ce3408b7ad0fd540171d31f9f \ + --hash=sha256:c7ea57fc63aa7da93a1bd2d644e6577befae10c52c4e36377635eea1056a74f5 \ + --hash=sha256:cd5214352ae68f3b5e9af7768bdc5253695ee069675db3480518420b3be881f2 \ + --hash=sha256:cdbb78909f52b981d3b2d56b97328d71eb0b974c36bd77c920123a7ebb192829 \ + --hash=sha256:cdc8b74ecc48c0cb1e9607a05ec4e9e88db60a19ffcc9a1d5f9088ede40c8dc0 \ + --hash=sha256:d0a24b40877af2de4950252be9d21eaf7fb07660f3c2cae1f56c6b599ada5266 \ + --hash=sha256:d22a945598fb91236b4dd793a6e42e4f3dd7740bb5aace5ebd7d4c08d13bb575 \ + --hash=sha256:d2f9fc07a8042a8f95925b35c4f04f469707c981fc33245b6ca187cf5d2dd290 \ + --hash=sha256:d625a186a65201c23a9e3b8ed9c47e90a026e03256608cc91851c6709096844f \ + --hash=sha256:d925f3d9afd05a8c0fb3a1031463a8d59ebe5e2afad297e29c78be19e13b4e62 \ + --hash=sha256:e64e88d5585bea9ce95861079de72006c7fa6d3df4e3a3b65ba31eb979c15c9f \ + --hash=sha256:e652ab17569c94bff5475520f907b7148b8c24036a8ebbe5cf7cf7493d28579a \ + --hash=sha256:e7b891faeedeafba41b2983e5001a81b6a915b69544c7e7570d1989ce1c36ac7 \ + --hash=sha256:e80675d75ae2cd14372cb65cad5400d9347a3d3f6c13000183f22dfd027283ed \ + --hash=sha256:e9c134bb666dd54b778b9fc0d2b50cbb7f979b9e3716f26a88c9ab3b6fc1dd0f \ + --hash=sha256:eb7d8d0e5886a89a55d2eef490e272fa965a9d57c6b29a5b5088a7997ec2cad1 \ + --hash=sha256:ecb42011e12ee19cafbc312887cbf3546959fe02fbad44f272d4be5baa997615 \ + --hash=sha256:ef3fbbf161dc9351a2fe0422e51b129f9e97e42385bd0320b309c15f7d287dd8 \ + --hash=sha256:efd62a42486f1bda5d24cb4f63d15a3c7768375fe83d36f9417b4ad7a2fb20b3 \ + --hash=sha256:f077d0b97ab11fa7dcc633fca53515f290bca8a8a633e966d5b6d1879d9ed01a \ + --hash=sha256:f332f0e72a5a0400141f830744e141bf9f97917878dbe968669e8a7fefea78ff \ + --hash=sha256:f7b0ec93a2893de856652154d73b7ba622f26fa97726487dcac373de5f4c6084 \ + --hash=sha256:fa10ef4112775900e7a0661068635eb67b2ab824fbde764de6e0e21982a93db0 \ + --hash=sha256:fc5d783bd4a2387e97b8a2d5ec781cfb92b3d893bf82370548e99db5915935d3 \ + --hash=sha256:fc8515076c11f3cfdf4fb142dcca0fe384b1230a3b5415458ac84f3e0903ec13 \ + --hash=sha256:ff218293c9c806138dca139765e3b067621be52bcd93cdc14c7711be7ddc90a9 + # via pydantic +pydantic-settings==2.15.0 \ + --hash=sha256:0ba092c291c94baceb5eff768aa0d56400a457585bc0175925a5a5510303da42 \ + --hash=sha256:694b793e84f766ba76a90ebdefc01d0a9a045dab0382bee70393da93712ad117 + # via mcp +pygments==2.21.0 \ + --hash=sha256:2363c69b61c4a97c838da3b130dcd6468f4848992b21a82f2a63ec34377137d9 \ + --hash=sha256:610ca751c9bc2492b38eb9a38a7fbc93edbbb2d7182edaf34e66ae493dee5c8c + # via rich +pyjwt==2.13.0 \ + --hash=sha256:41571c89ca91598c79e8ef18a2d07367d4810fbbd6f637794879baf1b7703423 \ + --hash=sha256:66adcc2aff09b3f1bbd95fc1e1577df8ac8723c978552fd43304c8a290ac5728 + # via + # mcp + # semgrep +python-dotenv==1.2.3 \ + --hash=sha256:904552145e8bfed22162c09dab1c2b9b54fefa7b23ba780f4f26ca0316b0f0d9 \ + --hash=sha256:a20a594dabeaa385725aa239d5244871c143ecb356add8a20fcf23773a6c3a35 + # via pydantic-settings +python-multipart==0.0.32 \ + --hash=sha256:be54b7f3fa167bb83e4fcd936b887b708f4e57fe75911c02aebf53efaf8d938e \ + --hash=sha256:ff6d3f776f16878c894e52e107296ffc890e913c611b1a4ec6c44e2821fe2e23 + # via mcp +referencing==0.37.0 \ + --hash=sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231 \ + --hash=sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8 + # via + # jsonschema + # jsonschema-specifications +requests==2.34.2 \ + --hash=sha256:2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0 \ + --hash=sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed + # via + # opentelemetry-exporter-otlp-proto-http + # semgrep +rich==15.0.0 \ + --hash=sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb \ + --hash=sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36 + # via semgrep +rpds-py==2026.6.3 \ + --hash=sha256:0be972be84cfcaf46c8c6edf690ca0f154ac17babf1f6a955a51579b34ad2dc5 \ + --hash=sha256:127565fead0a10943b282957bd5447804ff3160ad79f2ad2635e6d249e380680 \ + --hash=sha256:127e08c0642d880cf32ca47ec2a4a77b901f7e2dd1ad9762adb13955d72ffcc9 \ + --hash=sha256:166cf54d9f44fc6ceb53c7860258dde44a81406646de79f8ed3234fca3b6e538 \ + --hash=sha256:168c733a7112e071bb7a66460e667edfcff06c017a3c523f7a8a8e08d0140804 \ + --hash=sha256:1967debc37f64f2c4dc90a7f563aec558b471966e12adcac4e1c4240496b6ebf \ + --hash=sha256:1cebd1337c242e4ec2293e541f712b2da849b29f48f0c293684b71c0632625d4 \ + --hash=sha256:1cf01971c4f2c5553b772a542e4aaf191789cd331bc2cd4ff0e6e65ba49e1e97 \ + --hash=sha256:1e5822dfc2f0d4ab7e745eaa6d85945069329beeccef965af3f3bb26058fcab6 \ + --hash=sha256:22bffe6042b9bcb0822bcd1955ec00e245daf17b4344e4ed8e9551b976b63e96 \ + --hash=sha256:23a439f31ccbeff1574e24889128821d1f7917470e830cf6544dced1c662262a \ + --hash=sha256:24e9c5386e16669b674a69c156c8eeefcb578f3b3397b713b08e6d60f3c7b187 \ + --hash=sha256:270b293dae9058fc9fcedab50f13cebf46fb8ed1d1d54e0521a9da5d6b211975 \ + --hash=sha256:29dfa0533a5d4c94d4dfa1b694fcb56c9c63aad8330ffdd816fd225d0a7a162f \ + --hash=sha256:2a9c6f195058cb45335e8cc3802745c603d716eb96bc9625950c1aac71c0c703 \ + --hash=sha256:2bfd04c19ddbd6640de0b51894d764bd2758854d5b75bd102d2ef10cb9c293a9 \ + --hash=sha256:2c54a076ca4d370980ab57bc0e31df57bbe8d41340436a90ef8b1219a3cbb127 \ + --hash=sha256:2c958bf94822e9290a40aaf2a822d4bc5c88099093e3948ad6c571eca9272e5f \ + --hash=sha256:2c99f7e8ccb3dd6e3e4bfeac657a7b208c9bac8075f4b078c02d7404c34107fa \ + --hash=sha256:2f7c26fbc5acd2522b95d4177fe4710ffd8e9b20529e703ffbf8db4d93903f05 \ + --hash=sha256:30c6dc199b24a5e3e81d50da0f00858c5bbdb2617a750395687f4339c5818171 \ + --hash=sha256:38a2fea2787428f811719ceb9114cb78964a3138838320c29ac39526c79c16ba \ + --hash=sha256:3a83ae6c67b7676b9878378547ca8e93ed77a580037bcbcd1d32f739e1e6089c \ + --hash=sha256:3cfe765c1da0072636ca06628261e0ea05688e160d5c8a03e0217c3854037223 \ + --hash=sha256:421aba32367055614287a4292b6a17f1939c9452299f7a0209c117e990b646d4 \ + --hash=sha256:425560c6fa0415f27261727bb20bd097568485e5eb0c121f1949417d1c516885 \ + --hash=sha256:4470ce197d4090875cf6affbf1f853338387428df97c4fb7b7106317b8214698 \ + --hash=sha256:4cf2d36a2357e4d07bb5a4f98801265327b48256867816cfd2ceb001e9754a8f \ + --hash=sha256:4f4bca01b63096f606e095734dd56e74e175f94cfbf24ff3d63281cec61f7bb7 \ + --hash=sha256:501f9f04a588d6a09179368c57071301445191767c64e4b52a6aa9871f1ef5ed \ + --hash=sha256:536bceea4fa4acf7e1c61da2b5786304367c816c8895be71b8f537c480b0ea1f \ + --hash=sha256:538949e262e46caa31ac01bdb3c1e8f642622922cacbabbae6a8445d9dc33eaf \ + --hash=sha256:539d75de9e0d536c84ff18dfeb805398e58227001ce09231a26a08b9aed1ee0e \ + --hash=sha256:54f45a148e28767bf343d33a684693c70e451c6f4c0e9904709a723fafbdfc1f \ + --hash=sha256:55927d532399c2c646100ff7feb48eaa940ad70f42cd68e1328f3ded9f81ca24 \ + --hash=sha256:58eadac9cd119677b60e1cf8ac4052f35949d71b8a9e5556efccbe82533cf22a \ + --hash=sha256:5e8d07bddee435a2ff6f1920e18feff28d0bc4533e42f4bf6927fbd073312c41 \ + --hash=sha256:62698275682bf121181861295c9181e789030a2d516071f5b8f3c23c170cd0fc \ + --hash=sha256:639c8929aa0afe81be836b04de888460d6bed38b9c54cfc18da8f6bfabf5af5d \ + --hash=sha256:67e3a721ffc5d8d2210d3671872298c4a84e4b8035cfe42ffd7cde35d772b146 \ + --hash=sha256:6de4744d05bd1aa1be4ed7ea1189e3979196808008113bbbf899a460966b925e \ + --hash=sha256:6e84adbcf4bf841aed8116a8264b9f50b4cb3e7bd89b516122e616ac56ca269e \ + --hash=sha256:7491ee23305ac3eb59e492b6945881f5cd77a6f731061a3f25b77fd40f9e99a4 \ + --hash=sha256:79486287de1730dbaff3dbd124d0ca4d2ef7f9d29bf2544f1f93c09b5bcbbd12 \ + --hash=sha256:7b689145a1485c335569bd056464f3243a29af7ed3871c7be31ad624ba239bc7 \ + --hash=sha256:7f88d653e7b3b779d71ae7454e20dcc9b6bae903f33c269db9f2be41bda3f261 \ + --hash=sha256:8020133a74bd81b4572dd8e4be028a6b1ebcd70e6726edc3918008c08bee6ee6 \ + --hash=sha256:808345f53cb952433ca2816f1604ff3515608a81784954f38d4452acfe8e61d5 \ + --hash=sha256:83e35b57523816c8613fd0776b40cd8bb9f596b37ddd2692eb4a6bb5ab2f8c93 \ + --hash=sha256:842e7b070435622248c7a2c44ae53fa1440e073cc3023bc919fed570884097a7 \ + --hash=sha256:847927daf4cffbd4e90e42bc890069897101edd015f956cb8721b3473372edda \ + --hash=sha256:882076c00c0a608b131187055ddc5ae29f2e7eaf870d6168980420d58528a5c8 \ + --hash=sha256:8b95977e7211527ab0ba576e286d023389fbeeb32a6b7b771665d333c60e5342 \ + --hash=sha256:8bb68f03f395eb793220b45c097bd4d8c32944393da0fad8b999efac0868fc8c \ + --hash=sha256:8c2642a7603ec0b16ed77da4555db3b4b472341904873788327c0b0d7b95f1bb \ + --hash=sha256:8c3d1e9c15b9d51ca0391e13da1a25a0a4df3c58a37c9dc368e0736cf7f69df0 \ + --hash=sha256:8c6e5a2f750cc71c3e3b11d71661f21d6f9bc6cebc6564b1466417a1ec03ec77 \ + --hash=sha256:8d2294a31386bfa251d8c8a39472beee17db67d4f1a6eabea665d35c9a4461c3 \ + --hash=sha256:8e4320744c1ffdd95a603def63344bfab2d33edeab301c5007e7de9f9f5b3885 \ + --hash=sha256:8e65860d238379ed982fd9ba690579b5e95af2f4840f99c772816dbe573cb826 \ + --hash=sha256:8f2e5c5ee828d42cb11760761c0af6507927bec42d0ad5458f97c9203b054617 \ + --hash=sha256:900a67df3fd1660b035a4761c4ce73c382ea6b35f90f9863c36c6fd8bf8b09bb \ + --hash=sha256:913ca42ccad3f8cc6e292b587ae8ae49c8c823e5dce51a736252fc7c7cdfa577 \ + --hash=sha256:9250a9a0a6fd4648b3f868da8d91a4c52b5811a62df58e753d50ae4454a36f80 \ + --hash=sha256:931908d9fc855d8f74783377822be318edb6dcb19e47169dc038f9a1bf60b06e \ + --hash=sha256:9826217f048f620d9a712672818bf231442c1b35d96b227a07eabd11b4bb6945 \ + --hash=sha256:9891e594296ab9dada6551c8e7b387b2721f27a67eecd528412e8906247a7b90 \ + --hash=sha256:9c1255b302953c86a486b81d330d5ee1d5bd937691ce271b6be0ef0e299eaab7 \ + --hash=sha256:a0811d33247c3d6128a3001d763f2aa056bb3425204335400ac54f89eec3a0d0 \ + --hash=sha256:a136d453475ac0fcbda502ef1e6504bd28d6d904700915d278deeab0d00fe140 \ + --hash=sha256:a214c993455f99a89aaeadc9b21241900037adc9d97203e374d75513c5911822 \ + --hash=sha256:a3086b538543802f84c843911242db20447de00d8752dd0efc936dbcf02218ba \ + --hash=sha256:a3450b693fde92133e9f51060568a4c31fcca76d5e53bbd611e689ca446517e9 \ + --hash=sha256:a550fb4950a06dde3beb4721f5ad4b25bf4513784665b0a8522c792e2bd822a4 \ + --hash=sha256:a9f4645593036b81bbdb36b9c8e0ea0d1c3fee968c4d59db0344c14087ef143a \ + --hash=sha256:aca6c1ef08a82bfe327cc156da694660f599923e2e6665b6d81c9c2d0ac9ffc8 \ + --hash=sha256:acac386b453c2516111b50985d60ce46e7fadb5ea71ae7b25f4c946935bf27cf \ + --hash=sha256:acc992ab27b15f852c76755eb2ab7dce86585ddadba6fa5946e58556088845b4 \ + --hash=sha256:ae3d4fe8c0b9213624fdce7279d70e3b148b682ca20719ebd193a23ebfa47324 \ + --hash=sha256:ae50181a047c871561212bb97f7932a2d45fb53e947bd9b57ebad85b529cbc53 \ + --hash=sha256:ae6dd8f10bd17aad820876d24caec9efdafd80a318d16c0a48edb5e136902c6b \ + --hash=sha256:af05d726809bff6b141be124d4c7ce998f9c9c7f30edb1f46c07aa103d540b41 \ + --hash=sha256:afd70d95892096cdb26f15a00c45907b17817577aa8d1c76b2dcc2788391f9e9 \ + --hash=sha256:b5c2dc92304aa48a4a60443b548bb12f12e119d4b72f314015e67b9e1be97fca \ + --hash=sha256:bc0011654b91cc4fb2ae701bec0a0ba1e552c0714247fa7af6c59e0ccfa3a4e1 \ + --hash=sha256:bcfbcf66006befb9fd2aeaa9e01feaf881b4dc330a02ba07d2322b1c11be7b5d \ + --hash=sha256:bdbd97738551fca3917c1bd7188bec1920bb520104f28e7e1007f9ceb17b7690 \ + --hash=sha256:c60924535c75f1566b6eb75b5c31a48a43fef04fa2d0d201acbad8a9969c6107 \ + --hash=sha256:c7b9a2f8f4d8e90af72571d3d495deebdd7e3c75451f5b41719aee166e940fc2 \ + --hash=sha256:ca6546b66be9dc4738b1b043d5ebd5488c66c578c5ff0fd0e8065313fe3afb76 \ + --hash=sha256:ccffae9a092a00deb7efd545fe5e2c33c33b88e7c054337e9a74c179347d0b7d \ + --hash=sha256:cdc7e35386f3847df728fbcb5e887e2d79c19e2fa1eba9e51b6621d23e3243af \ + --hash=sha256:d15fde0e6fb0d88a60d221204873743e5d9f0b7d29165e62cd86d0413ad74ba6 \ + --hash=sha256:d34c20167764fbcf927194d532dd7e0c56772f0a5f943fa5ef9e9afbba8fb9db \ + --hash=sha256:d483fe17f01ad64b7bf7cc38fcefff1ca9fb83f8c2b2542b68f97ffe0611b369 \ + --hash=sha256:d7469697dce35be237db177d42e2a2ee26e6dcc5fc052078a6fefabd288c6edd \ + --hash=sha256:db08f45aecde626498fb3df07bcf6d2ec040af42e859a4f5040d79c200342911 \ + --hash=sha256:dc319e5a1de4b6913aac94bf6a2f9e847371e0a140a43dd4991db1a09bc2d504 \ + --hash=sha256:de3eceba0b683bcbb1ab93da016d0270df1f9ae7be716b40214c5dafac6ea45a \ + --hash=sha256:dfcc8b909769d19db55c7cc9541eb64b9b774b1057ffffb4f1048070475bb9f9 \ + --hash=sha256:e059c5dde6452b44424bd1834557556c226b57781dee1227af23518459722b13 \ + --hash=sha256:e4316bf32babbed84e691e352faf967ce2f0f024174a8643c37c94a1080374fc \ + --hash=sha256:e52655eaf81e32593abedaa4bfe33170c8cfedf3365ed9be6e11e07f148f0278 \ + --hash=sha256:e55d236be29255554da47abe5c577637db7c24a02b8b46f0ca9524c855801868 \ + --hash=sha256:ea7bb13b7c9a29791f87a0387ba7d3ad3a6d783d827e4d3f27b40a0ff44495e2 \ + --hash=sha256:ea964164cc9afa72d4d9b23cc28dafae93693c0a53e0b42acbff15b22c3f9ddd \ + --hash=sha256:ec829541c45bca16e61c7ae50c20501f213605beb75d1aba91a6ee37fbbb56a4 \ + --hash=sha256:ecabd69db66de867690f9797f2f8fa27ba501bbc24540cbdbdc649cd15888ba6 \ + --hash=sha256:ed0c1e5d10cdc7135537988c74a0188da68e2f3c30813ba3744ab1e42e0480f9 \ + --hash=sha256:f0840b5b17057f7fd918b76183a4b5a0635f43e14eb2ce60dce1d4ee4707ea00 \ + --hash=sha256:f4d78253f6996be4901669ad25319f842f740eccf4d58e3c7f3dd39e6dde1d8f \ + --hash=sha256:f56f1695bc5c0871cbc33dc0130fcf503aab0c57dcc5a6700a4f49eba4f2652e \ + --hash=sha256:f826877d462181e5eb1c26a0026b8d0cab05d99844ecb6d8bf3627a2ca0c0442 \ + --hash=sha256:f8f23ead891a3b762f35ab3b04623da7056545b48aa60d59957e6789914545da \ + --hash=sha256:f90938e92afda60266da758ee7d363447f7f0138c9559f9e1811629580582d90 \ + --hash=sha256:faa679d19a6696fd54259ad321251ad77a13e70e03dd834daa762a44fb6196ef + # via + # jsonschema + # referencing +ruamel-yaml==0.19.1 \ + --hash=sha256:27592957fedf6e0b62f281e96effd28043345e0e66001f97683aa9a40c667c93 \ + --hash=sha256:53eb66cd27849eff968ebf8f0bf61f46cdac2da1d1f3576dd4ccee9b25c31993 + # via semgrep +ruamel-yaml-clib==0.2.15 \ + --hash=sha256:014181cdec565c8745b7cbc4de3bf2cc8ced05183d986e6d1200168e5bb59490 \ + --hash=sha256:04d21dc9c57d9608225da28285900762befbb0165ae48482c15d8d4989d4af14 \ + --hash=sha256:05c70f7f86be6f7bee53794d80050a28ae7e13e4a0087c1839dcdefd68eb36b6 \ + --hash=sha256:0ba6604bbc3dfcef844631932d06a1a4dcac3fee904efccf582261948431628a \ + --hash=sha256:11e5499db1ccbc7f4b41f0565e4f799d863ea720e01d3e99fa0b7b5fcd7802c9 \ + --hash=sha256:1b45498cc81a4724a2d42273d6cfc243c0547ad7c6b87b4f774cb7bcc131c98d \ + --hash=sha256:1bb7b728fd9f405aa00b4a0b17ba3f3b810d0ccc5f77f7373162e9b5f0ff75d5 \ + --hash=sha256:1f66f600833af58bea694d5892453f2270695b92200280ee8c625ec5a477eed3 \ + --hash=sha256:27dc656e84396e6d687f97c6e65fb284d100483628f02d95464fd731743a4afe \ + --hash=sha256:2812ff359ec1f30129b62372e5f22a52936fac13d5d21e70373dbca5d64bb97c \ + --hash=sha256:2b216904750889133d9222b7b873c199d48ecbb12912aca78970f84a5aa1a4bc \ + --hash=sha256:331fb180858dd8534f0e61aa243b944f25e73a4dae9962bd44c46d1761126bbf \ + --hash=sha256:3cb75a3c14f1d6c3c2a94631e362802f70e83e20d1f2b2ef3026c05b415c4900 \ + --hash=sha256:3eb199178b08956e5be6288ee0b05b2fb0b5c1f309725ad25d9c6ea7e27f962a \ + --hash=sha256:424ead8cef3939d690c4b5c85ef5b52155a231ff8b252961b6516ed7cf05f6aa \ + --hash=sha256:45702dfbea1420ba3450bb3dd9a80b33f0badd57539c6aac09f42584303e0db6 \ + --hash=sha256:468858e5cbde0198337e6a2a78eda8c3fb148bdf4c6498eaf4bc9ba3f8e780bd \ + --hash=sha256:46895c17ead5e22bea5e576f1db7e41cb273e8d062c04a6a49013d9f60996c25 \ + --hash=sha256:46e4cc8c43ef6a94885f72512094e482114a8a706d3c555a34ed4b0d20200600 \ + --hash=sha256:480894aee0b29752560a9de46c0e5f84a82602f2bc5c6cde8db9a345319acfdf \ + --hash=sha256:4b293a37dc97e2b1e8a1aec62792d1e52027087c8eea4fc7b5abd2bdafdd6642 \ + --hash=sha256:4be366220090d7c3424ac2b71c90d1044ea34fca8c0b88f250064fd06087e614 \ + --hash=sha256:4d1032919280ebc04a80e4fb1e93f7a738129857eaec9448310e638c8bccefcf \ + --hash=sha256:4d3b58ab2454b4747442ac76fab66739c72b1e2bb9bd173d7694b9f9dbc9c000 \ + --hash=sha256:4dcec721fddbb62e60c2801ba08c87010bd6b700054a09998c4d09c08147b8fb \ + --hash=sha256:512571ad41bba04eac7268fe33f7f4742210ca26a81fe0c75357fa682636c690 \ + --hash=sha256:542d77b72786a35563f97069b9379ce762944e67055bea293480f7734b2c7e5e \ + --hash=sha256:56ea19c157ed8c74b6be51b5fa1c3aff6e289a041575f0556f66e5fb848bb137 \ + --hash=sha256:5d3c9210219cbc0f22706f19b154c9a798ff65a6beeafbf77fc9c057ec806f7d \ + --hash=sha256:5fea0932358e18293407feb921d4f4457db837b67ec1837f87074667449f9401 \ + --hash=sha256:617d35dc765715fa86f8c3ccdae1e4229055832c452d4ec20856136acc75053f \ + --hash=sha256:64da03cbe93c1e91af133f5bec37fd24d0d4ba2418eaf970d7166b0a26a148a2 \ + --hash=sha256:65f48245279f9bb301d1276f9679b82e4c080a1ae25e679f682ac62446fac471 \ + --hash=sha256:6f1d38cbe622039d111b69e9ca945e7e3efebb30ba998867908773183357f3ed \ + --hash=sha256:713cd68af9dfbe0bb588e144a61aad8dcc00ef92a82d2e87183ca662d242f524 \ + --hash=sha256:71845d377c7a47afc6592aacfea738cc8a7e876d586dfba814501d8c53c1ba60 \ + --hash=sha256:753faf20b3a5906faf1fc50e4ddb8c074cb9b251e00b14c18b28492f933ac8ef \ + --hash=sha256:7e74ea87307303ba91073b63e67f2c667e93f05a8c63079ee5b7a5c8d0d7b043 \ + --hash=sha256:88eea8baf72f0ccf232c22124d122a7f26e8a24110a0273d9bcddcb0f7e1fa03 \ + --hash=sha256:923816815974425fbb1f1bf57e85eca6e14d8adc313c66db21c094927ad01815 \ + --hash=sha256:9b6f7d74d094d1f3a4e157278da97752f16ee230080ae331fcc219056ca54f77 \ + --hash=sha256:a8220fd4c6f98485e97aea65e1df76d4fed1678ede1fe1d0eed2957230d287c4 \ + --hash=sha256:ab0df0648d86a7ecbd9c632e8f8d6b21bb21b5fc9d9e095c796cacf32a728d2d \ + --hash=sha256:ac9b8d5fa4bb7fd2917ab5027f60d4234345fd366fe39aa711d5dca090aa1467 \ + --hash=sha256:badd1d7283f3e5894779a6ea8944cc765138b96804496c91812b2829f70e18a7 \ + --hash=sha256:bdc06ad71173b915167702f55d0f3f027fc61abd975bd308a0968c02db4a4c3e \ + --hash=sha256:bf0846d629e160223805db9fe8cc7aec16aaa11a07310c50c8c7164efa440aec \ + --hash=sha256:bfd309b316228acecfa30670c3887dcedf9b7a44ea39e2101e75d2654522acd4 \ + --hash=sha256:c583229f336682b7212a43d2fa32c30e643d3076178fb9f7a6a14dde85a2d8bd \ + --hash=sha256:cb15a2e2a90c8475df45c0949793af1ff413acfb0a716b8b94e488ea95ce7cff \ + --hash=sha256:d290eda8f6ada19e1771b54e5706b8f9807e6bb08e873900d5ba114ced13e02c \ + --hash=sha256:da3d6adadcf55a93c214d23941aef4abfd45652110aed6580e814152f385b862 \ + --hash=sha256:dcc7f3162d3711fd5d52e2267e44636e3e566d1e5675a5f0b30e98f2c4af7974 \ + --hash=sha256:def5663361f6771b18646620fca12968aae730132e104688766cf8a3b1d65922 \ + --hash=sha256:e5e9f630c73a490b758bf14d859a39f375e6999aea5ddd2e2e9da89b9953486a \ + --hash=sha256:e9fde97ecb7bb9c41261c2ce0da10323e9227555c674989f8d9eb7572fc2098d \ + --hash=sha256:ef71831bd61fbdb7aa0399d5c4da06bea37107ab5c79ff884cc07f2450910262 \ + --hash=sha256:f4421ab780c37210a07d138e56dd4b51f8642187cdfb433eb687fe8c11de0144 \ + --hash=sha256:f6d3655e95a80325b84c4e14c080b2470fe4f33b6846f288379ce36154993fb1 \ + --hash=sha256:fd4c928ddf6bce586285daa6d90680b9c291cfd045fc40aad34e445d57b1bf51 \ + --hash=sha256:fe239bdfdae2302e93bd6e8264bd9b71290218fff7084a9db250b55caaccf43f + # via semgrep +semantic-version==2.10.0 \ + --hash=sha256:bdabb6d336998cbb378d4b9db3a4b56a1e3235701dc05ea2690d9a997ed5041c \ + --hash=sha256:de78a3b8e0feda74cabc54aab2da702113e33ac9d9eb9d2389bcf1f58b7d9177 + # via semgrep +semgrep==1.176.1 \ + --hash=sha256:00bc0f167564443d7ce4ad7a896d2251ed3c5c17e0b176de9b39bd0fb6abc2a9 \ + --hash=sha256:2214b71919b825766844ce3dc8c868965d98c3109628882357461ba2a1b8def7 \ + --hash=sha256:5ca9822b9b8d645b6f078160139b966bd66a3829b87c4e63e1bb5f8d7f71732f \ + --hash=sha256:5f1127deb8df4e671bae2ec6c811cb069df29fae66bf4880bdad135f38629b23 \ + --hash=sha256:670e2dc84cc9b7a3b42e42e0b7137b06638cad49cb3166a57377257137d21bad \ + --hash=sha256:9baed01491cbe1de00f862f73349bf1c9045598bae2923f6a19ef453b3092015 \ + --hash=sha256:ce35dc0b9c34bb95e16f487699646a461e9b2aceda073e773526e0836dbf73ba \ + --hash=sha256:e1f78275f13c11bd9b6af1143befd79d333d948bd4af96768be3494ab342d8f3 + # via -r .github/requirements/semgrep.in +sse-starlette==3.4.11 \ + --hash=sha256:1bae716c02f3e6f294be41ff333220692dae7c3cbab077c900f159676719dade \ + --hash=sha256:c7b2244bdff016fe7f64e10075e89a3e6bbf899649cc89b0fe884b5545042453 + # via mcp +starlette==1.6.0 \ + --hash=sha256:a86dd39d14bb45f85a3d18525215a9ef0cfd1f192ac793220e72598c90335f0c \ + --hash=sha256:d4e3ac5e546444960c710297a3c9fc3f7ebae1b7e963f3d36173b49da535be9b + # via + # mcp + # sse-starlette +tomli==2.4.1 \ + --hash=sha256:01f520d4f53ef97964a240a035ec2a869fe1a37dde002b57ebc4417a27ccd853 \ + --hash=sha256:0d85819802132122da43cb86656f8d1f8c6587d54ae7dcaf30e90533028b49fe \ + --hash=sha256:136443dbd7e1dee43c68ac2694fde36b2849865fa258d39bf822c10e8068eac5 \ + --hash=sha256:1d8591993e228b0c930c4bb0db464bdad97b3289fb981255d6c9a41aedc84b2d \ + --hash=sha256:2190f2e9dd7508d2a90ded5ed369255980a1bcdd58e52f7fe24b8162bf9fedbd \ + --hash=sha256:2c1c351919aca02858f740c6d33adea0c5deea37f9ecca1cc1ef9e884a619d26 \ + --hash=sha256:36d2bd2ad5fb9eaddba5226aa02c8ec3fa4f192631e347b3ed28186d43be6b54 \ + --hash=sha256:3d48a93ee1c9b79c04bb38772ee1b64dcf18ff43085896ea460ca8dec96f35f6 \ + --hash=sha256:47149d5bd38761ac8be13a84864bf0b7b70bc051806bc3669ab1cbc56216b23c \ + --hash=sha256:4ab97e64ccda8756376892c53a72bd1f964e519c77236368527f758fbc36a53a \ + --hash=sha256:4b605484e43cdc43f0954ddae319fb75f04cc10dd80d830540060ee7cd0243cd \ + --hash=sha256:504aa796fe0569bb43171066009ead363de03675276d2d121ac1a4572397870f \ + --hash=sha256:51529d40e3ca50046d7606fa99ce3956a617f9b36380da3b7f0dd3dd28e68cb5 \ + --hash=sha256:52c8ef851d9a240f11a88c003eacb03c31fc1c9c4ec64a99a0f922b93874fda9 \ + --hash=sha256:559db847dc486944896521f68d8190be1c9e719fced785720d2216fe7022b662 \ + --hash=sha256:5a881ab208c0baf688221f8cecc5401bd291d67e38a1ac884d6736cbcd8247e9 \ + --hash=sha256:5cb41aa38891e073ee49d55fbc7839cfdb2bc0e600add13874d048c94aadddd1 \ + --hash=sha256:5e262d41726bc187e69af7825504c933b6794dc3fbd5945e41a79bb14c31f585 \ + --hash=sha256:5ee18d9ebdb417e384b58fe414e8d6af9f4e7a0ae761519fb50f721de398dd4e \ + --hash=sha256:7008df2e7655c495dd12d2a4ad038ff878d4ca4b81fccaf82b714e07eae4402c \ + --hash=sha256:734e20b57ba95624ecf1841e72b53f6e186355e216e5412de414e3c51e5e3c41 \ + --hash=sha256:7c7e1a961a0b2f2472c1ac5b69affa0ae1132c39adcb67aba98568702b9cc23f \ + --hash=sha256:7f86fd587c4ed9dd76f318225e7d9b29cfc5a9d43de44e5754db8d1128487085 \ + --hash=sha256:7f94b27a62cfad8496c8d2513e1a222dd446f095fca8987fceef261225538a15 \ + --hash=sha256:88dceee75c2c63af144e456745e10101eb67361050196b0b6af5d717254dddf7 \ + --hash=sha256:8a650c2dbafa08d42e51ba0b62740dae4ecb9338eefa093aa5c78ceb546fcd5c \ + --hash=sha256:8d65a2fbf9d2f8352685bc1364177ee3923d6baf5e7f43ea4959d7d8bc326a36 \ + --hash=sha256:96481a5786729fd470164b47cdb3e0e58062a496f455ee41b4403be77cb5a076 \ + --hash=sha256:a120733b01c45e9a0c34aeef92bf0cf1d56cfe81ed9d47d562f9ed591a9828ac \ + --hash=sha256:b1d22e6e9387bf4739fbe23bfa80e93f6b0373a7f1b96c6227c32bef95a4d7a8 \ + --hash=sha256:b8c198f8c1805dc42708689ed6864951fd2494f924149d3e4bce7710f8eb5232 \ + --hash=sha256:c2541745709bad0264b7d4705ad453b76ccd191e64aa6f0fc66b69a293a45ece \ + --hash=sha256:c742f741d58a28940ce01d58f0ab2ea3ced8b12402f162f4d534dfe18ba1cd6a \ + --hash=sha256:c7f2c7f2b9ca6bdeef8f0fa897f8e05085923eb091721675170254cbc5b02897 \ + --hash=sha256:d312ef37c91508b0ab2cee7da26ec0b3ed2f03ce12bd87a588d771ae15dcf82d \ + --hash=sha256:d4d8fe59808a54658fcc0160ecfb1b30f9089906c50b23bcb4c69eddc19ec2b4 \ + --hash=sha256:da25dc3563bff5965356133435b757a795a17b17d01dbc0f42fb32447ddfd917 \ + --hash=sha256:eab21f45c7f66c13f2a9e0e1535309cee140182a9cdae1e041d02e47291e8396 \ + --hash=sha256:eb0dc4e38e6a1fd579e5d50369aa2e10acfc9cace504579b2faabb478e76941a \ + --hash=sha256:ec9bfaf3ad2df51ace80688143a6a4ebc09a248f6ff781a9945e51937008fcbc \ + --hash=sha256:ede3e6487c5ef5d28634ba3f31f989030ad6af71edfb0055cbbd14189ff240ba \ + --hash=sha256:f3c6818a1a86dd6dca7ddcaaf76947d5ba31aecc28cb1b67009a5877c9a64f3f \ + --hash=sha256:f758f1b9299d059cc3f6546ae2af89670cb1c4d48ea29c3cacc4fe7de3058257 \ + --hash=sha256:f8f0fc26ec2cc2b965b7a3b87cd19c5c6b8c5e5f436b984e85f486d652285c30 \ + --hash=sha256:fd0409a3653af6c147209d267a0e4243f0ae46b011aa978b1080359fddc9b6cf \ + --hash=sha256:ff18e6a727ee0ab0388507b89d1bc6a22b138d1e2fa56d1ad494586d61d2eae9 \ + --hash=sha256:ff2983983d34813c1aeb0fa89091e76c3a22889ee83ab27c5eeb45100560c049 + # via semgrep +typing-extensions==4.16.0 \ + --hash=sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8 \ + --hash=sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5 + # via + # anyio + # mcp + # opentelemetry-api + # opentelemetry-exporter-otlp-proto-http + # opentelemetry-sdk + # opentelemetry-semantic-conventions + # pydantic + # pydantic-core + # referencing + # semgrep + # starlette + # typing-inspection +typing-inspection==0.4.4 \ + --hash=sha256:547274fa6b0a561ccf549cc9524b999a578e737d015d8709d021f9d0d13bea47 \ + --hash=sha256:65b8397ba37ccbce054456aaccddfc91e6e3083c92824df348d96ca832f3f147 + # via + # mcp + # pydantic + # pydantic-settings +urllib3==2.7.0 \ + --hash=sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c \ + --hash=sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897 + # via + # requests + # semgrep +uvicorn==0.52.4 \ + --hash=sha256:73acfee47a0b133c5de13d219492d62d8a31e935f4fe6e41a232451a15379f86 \ + --hash=sha256:f86e41a149d7d05a9969337e3946a9c171c06a5d42680896daaba624aeac8da1 + # via mcp +wcmatch==8.5.2 \ + --hash=sha256:17d3ad3758f9d0b5b4dedc770b65420d4dac62e680229c287bf24c9db856a478 \ + --hash=sha256:a70222b86dea82fb382dd87b73278c10756c138bd6f8f714e2183128887b9eb2 + # via semgrep +wrapt==1.17.3 \ + --hash=sha256:02b551d101f31694fc785e58e0720ef7d9a10c4e62c1c9358ce6f63f23e30a56 \ + --hash=sha256:042ec3bb8f319c147b1301f2393bc19dba6e176b7da446853406d041c36c7828 \ + --hash=sha256:0610b46293c59a3adbae3dee552b648b984176f8562ee0dba099a56cfbe4df1f \ + --hash=sha256:0b02e424deef65c9f7326d8c19220a2c9040c51dc165cddb732f16198c168396 \ + --hash=sha256:0b1831115c97f0663cb77aa27d381237e73ad4f721391a9bfb2fe8bc25fa6e77 \ + --hash=sha256:0ed61b7c2d49cee3c027372df5809a59d60cf1b6c2f81ee980a091f3afed6a2d \ + --hash=sha256:0f5f51a6466667a5a356e6381d362d259125b57f059103dd9fdc8c0cf1d14139 \ + --hash=sha256:16ecf15d6af39246fe33e507105d67e4b81d8f8d2c6598ff7e3ca1b8a37213f7 \ + --hash=sha256:1f0b2f40cf341ee8cc1a97d51ff50dddb9fcc73241b9143ec74b30fc4f44f6cb \ + --hash=sha256:1f23fa283f51c890eda8e34e4937079114c74b4c81d2b2f1f1d94948f5cc3d7f \ + --hash=sha256:223db574bb38637e8230eb14b185565023ab624474df94d2af18f1cdb625216f \ + --hash=sha256:249f88ed15503f6492a71f01442abddd73856a0032ae860de6d75ca62eed8067 \ + --hash=sha256:24c2ed34dc222ed754247a2702b1e1e89fdbaa4016f324b4b8f1a802d4ffe87f \ + --hash=sha256:273a736c4645e63ac582c60a56b0acb529ef07f78e08dc6bfadf6a46b19c0da7 \ + --hash=sha256:281262213373b6d5e4bb4353bc36d1ba4084e6d6b5d242863721ef2bf2c2930b \ + --hash=sha256:30ce38e66630599e1193798285706903110d4f057aab3168a34b7fdc85569afc \ + --hash=sha256:33486899acd2d7d3066156b03465b949da3fd41a5da6e394ec49d271baefcf05 \ + --hash=sha256:343e44b2a8e60e06a7e0d29c1671a0d9951f59174f3709962b5143f60a2a98bd \ + --hash=sha256:373342dd05b1d07d752cecbec0c41817231f29f3a89aa8b8843f7b95992ed0c7 \ + --hash=sha256:3af60380ba0b7b5aeb329bc4e402acd25bd877e98b3727b0135cb5c2efdaefe9 \ + --hash=sha256:3e62d15d3cfa26e3d0788094de7b64efa75f3a53875cdbccdf78547aed547a81 \ + --hash=sha256:41b1d2bc74c2cac6f9074df52b2efbef2b30bdfe5f40cb78f8ca22963bc62977 \ + --hash=sha256:423ed5420ad5f5529db9ce89eac09c8a2f97da18eb1c870237e84c5a5c2d60aa \ + --hash=sha256:46acc57b331e0b3bcb3e1ca3b421d65637915cfcd65eb783cb2f78a511193f9b \ + --hash=sha256:4da9f45279fff3543c371d5ababc57a0384f70be244de7759c85a7f989cb4ebe \ + --hash=sha256:507553480670cab08a800b9463bdb881b2edeed77dc677b0a5915e6106e91a58 \ + --hash=sha256:53e5e39ff71b3fc484df8a522c933ea2b7cdd0d5d15ae82e5b23fde87d44cbd8 \ + --hash=sha256:54a30837587c6ee3cd1a4d1c2ec5d24e77984d44e2f34547e2323ddb4e22eb77 \ + --hash=sha256:5531d911795e3f935a9c23eb1c8c03c211661a5060aab167065896bbf62a5f85 \ + --hash=sha256:55cbbc356c2842f39bcc553cf695932e8b30e30e797f961860afb308e6b1bb7c \ + --hash=sha256:59923aa12d0157f6b82d686c3fd8e1166fa8cdfb3e17b42ce3b6147ff81528df \ + --hash=sha256:5a03a38adec8066d5a37bea22f2ba6bbf39fcdefbe2d91419ab864c3fb515454 \ + --hash=sha256:5a7b3c1ee8265eb4c8f1b7d29943f195c00673f5ab60c192eba2d4a7eae5f46a \ + --hash=sha256:5d4478d72eb61c36e5b446e375bbc49ed002430d17cdec3cecb36993398e1a9e \ + --hash=sha256:5ea5eb3c0c071862997d6f3e02af1d055f381b1d25b286b9d6644b79db77657c \ + --hash=sha256:604d076c55e2fdd4c1c03d06dc1a31b95130010517b5019db15365ec4a405fc6 \ + --hash=sha256:656873859b3b50eeebe6db8b1455e99d90c26ab058db8e427046dbc35c3140a5 \ + --hash=sha256:65d1d00fbfb3ea5f20add88bbc0f815150dbbde3b026e6c24759466c8b5a9ef9 \ + --hash=sha256:6b538e31eca1a7ea4605e44f81a48aa24c4632a277431a6ed3f328835901f4fd \ + --hash=sha256:6fd1ad24dc235e4ab88cda009e19bf347aabb975e44fd5c2fb22a3f6e4141277 \ + --hash=sha256:70d86fa5197b8947a2fa70260b48e400bf2ccacdcab97bb7de47e3d1e6312225 \ + --hash=sha256:7171ae35d2c33d326ac19dd8facb1e82e5fd04ef8c6c0e394d7af55a55051c22 \ + --hash=sha256:73d496de46cd2cdbdbcce4ae4bcdb4afb6a11234a1df9c085249d55166b95116 \ + --hash=sha256:7425ac3c54430f5fc5e7b6f41d41e704db073309acfc09305816bc6a0b26bb16 \ + --hash=sha256:74afa28374a3c3a11b3b5e5fca0ae03bef8450d6aa3ab3a1e2c30e3a75d023dc \ + --hash=sha256:758895b01d546812d1f42204bd443b8c433c44d090248bf22689df673ccafe00 \ + --hash=sha256:79573c24a46ce11aab457b472efd8d125e5a51da2d1d24387666cd85f54c05b2 \ + --hash=sha256:7e18f01b0c3e4a07fe6dfdb00e29049ba17eadbc5e7609a2a3a4af83ab7d710a \ + --hash=sha256:88547535b787a6c9ce4086917b6e1d291aa8ed914fdd3a838b3539dc95c12804 \ + --hash=sha256:88bbae4d40d5a46142e70d58bf664a89b6b4befaea7b2ecc14e03cedb8e06c04 \ + --hash=sha256:8cccf4f81371f257440c88faed6b74f1053eef90807b77e31ca057b2db74edb1 \ + --hash=sha256:9baa544e6acc91130e926e8c802a17f3b16fbea0fd441b5a60f5cf2cc5c3deba \ + --hash=sha256:a36692b8491d30a8c75f1dfee65bef119d6f39ea84ee04d9f9311f83c5ad9390 \ + --hash=sha256:a47681378a0439215912ef542c45a783484d4dd82bac412b71e59cf9c0e1cea0 \ + --hash=sha256:a7c06742645f914f26c7f1fa47b8bc4c91d222f76ee20116c43d5ef0912bba2d \ + --hash=sha256:a9a2203361a6e6404f80b99234fe7fb37d1fc73487b5a78dc1aa5b97201e0f22 \ + --hash=sha256:ab232e7fdb44cdfbf55fc3afa31bcdb0d8980b9b95c38b6405df2acb672af0e0 \ + --hash=sha256:ad85e269fe54d506b240d2d7b9f5f2057c2aa9a2ea5b32c66f8902f768117ed2 \ + --hash=sha256:af338aa93554be859173c39c85243970dc6a289fa907402289eeae7543e1ae18 \ + --hash=sha256:afd964fd43b10c12213574db492cb8f73b2f0826c8df07a68288f8f19af2ebe6 \ + --hash=sha256:b32888aad8b6e68f83a8fdccbf3165f5469702a7544472bdf41f582970ed3311 \ + --hash=sha256:c31eebe420a9a5d2887b13000b043ff6ca27c452a9a22fa71f35f118e8d4bf89 \ + --hash=sha256:caea3e9c79d5f0d2c6d9ab96111601797ea5da8e6d0723f77eabb0d4068d2b2f \ + --hash=sha256:cf30f6e3c077c8e6a9a7809c94551203c8843e74ba0c960f4a98cd80d4665d39 \ + --hash=sha256:d40770d7c0fd5cbed9d84b2c3f2e156431a12c9a37dc6284060fb4bec0b7ffd4 \ + --hash=sha256:d8a210b158a34164de8bb68b0e7780041a903d7b00c87e906fb69928bf7890d5 \ + --hash=sha256:dc4a8d2b25efb6681ecacad42fca8859f88092d8732b170de6a5dddd80a1c8fa \ + --hash=sha256:df7d30371a2accfe4013e90445f6388c570f103d61019b6b7c57e0265250072a \ + --hash=sha256:e01375f275f010fcbf7f643b4279896d04e571889b8a5b3f848423d91bf07050 \ + --hash=sha256:e1a4120ae5705f673727d3253de3ed0e016f7cd78dc463db1b31e2463e1f3cf6 \ + --hash=sha256:e228514a06843cae89621384cfe3a80418f3c04aadf8a3b14e46a7be704e4235 \ + --hash=sha256:e405adefb53a435f01efa7ccdec012c016b5a1d3f35459990afc39b6be4d5056 \ + --hash=sha256:e6b13af258d6a9ad602d57d889f83b9d5543acd471eee12eb51f5b01f8eb1bc2 \ + --hash=sha256:e6f40a8aa5a92f150bdb3e1c44b7e98fb7113955b2e5394122fa5532fec4b418 \ + --hash=sha256:e71d5c6ebac14875668a1e90baf2ea0ef5b7ac7918355850c0908ae82bcb297c \ + --hash=sha256:ed7c635ae45cfbc1a7371f708727bf74690daedc49b4dba310590ca0bd28aa8a \ + --hash=sha256:f38e60678850c42461d4202739f9bf1e3a737c7ad283638251e79cc49effb6b6 \ + --hash=sha256:f66eb08feaa410fe4eebd17f2a2c8e2e46d3476e9f8c783daa8e09e0faa666d0 \ + --hash=sha256:f9b2601381be482f70e5d1051a5965c25fb3625455a2bf520b5a077b22afb775 \ + --hash=sha256:fbd3c8319de8e1dc79d346929cd71d523622da527cca14e0c1d257e31c2b8b10 \ + --hash=sha256:fd341868a4b6714a5962c1af0bd44f7c404ef78720c7de4892901e540417111c + # via + # opentelemetry-instrumentation + # opentelemetry-instrumentation-threading +zipp==4.1.0 \ + --hash=sha256:25ad4e16390cd314347dd8f1de67a2ac538ae658ed4ab9db16029c07c188e97f \ + --hash=sha256:4cb57381f544315db7688e976e922a2b18cdb513d21cc194eb42232ba2a3e602 + # via importlib-metadata diff --git a/.github/workflows/jobs.yaml b/.github/workflows/jobs.yaml index f610ecf968..9de84a89ba 100644 --- a/.github/workflows/jobs.yaml +++ b/.github/workflows/jobs.yaml @@ -23,8 +23,6 @@ concurrency: cancel-in-progress: true env: - FIREFOX_VERSION: latest - TESTCAFE_VERSION: 3.7.6 # Historical test recipes call this MINIO_VERSION. The release gate uses the # maintained SILO server; upstream MinIO is probed separately as best effort. MINIO_VERSION: docker.io/pgsty/silo:RELEASE.2026-08-06T00-00-00Z @@ -39,10 +37,10 @@ jobs: os: [ubuntu-latest] steps: - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }} - uses: actions/setup-go@v7 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version: ${{ matrix.go-version }} id: go @@ -62,9 +60,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Set up Go 1.27.1 - uses: actions/setup-go@v7 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version: 1.27.1 - name: Remove the maintained mc replacement and probe compatibility @@ -77,9 +75,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Set up Go 1.27.1 - uses: actions/setup-go@v7 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version: 1.27.1 - name: Verify the README block against go.mod @@ -97,15 +95,18 @@ jobs: os: [ubuntu-latest] steps: - name: Check out source code - uses: actions/checkout@v6 - - name: Scanning code on ${{ matrix.os }} - continue-on-error: false + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + - name: Set up the pinned Semgrep Python runtime + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 + with: + python-version: "3.12.12" + cache: pip + cache-dependency-path: .github/requirements/semgrep.txt + - name: Install and run the locked Semgrep tool graph run: | - # Install semgrep rather than using a container due to: - # https://github.com/actions/checkout/issues/334 - sudo apt install -y python3-pip || apt install -y python3-pip - pip3 install semgrep - semgrep --config semgrep.yaml $(pwd)/web-app --error + python -m pip install --require-hashes -r .github/requirements/semgrep.txt + semgrep --config semgrep.yaml web-app --error --metrics off + python hack/check-ci-contract.py ui-assets: name: "React Code Has No Warnings & Prettified" @@ -116,18 +117,18 @@ jobs: os: [ubuntu-latest] steps: - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Read .nvmrc id: node_version run: echo "$(cat .nvmrc)" && echo "NVMRC=$(cat .nvmrc)" >> $GITHUB_ENV - name: Enable Corepack run: corepack enable - - uses: actions/setup-node@v6 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.0.0 with: node-version: ${{ env.NVMRC }} cache: "yarn" cache-dependency-path: web-app/yarn.lock - - uses: actions/cache@v5 + - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 id: assets-cache name: Assets Cache with: @@ -155,7 +156,7 @@ jobs: run: | ./check-deadcode.sh - name: Set up Go for the credits check - uses: actions/setup-go@v7 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version: ${{ matrix.go-version }} - name: Check the frontend section of CREDITS @@ -168,24 +169,36 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: fetch-depth: 0 - name: Set up Go 1.27.1 - uses: actions/setup-go@v7 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version: 1.27.1 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v4 + uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0 with: version: v0.36.1 - name: Install GoReleaser - uses: goreleaser/goreleaser-action@v7 + uses: goreleaser/goreleaser-action@f06c13b6b1a9625abc9e6e439d9c05a8f2190e94 # v7.2.3 with: version: v2.17.1 install-only: true + - name: Install Syft for release SBOM validation + uses: anchore/sbom-action/download-syft@3ad7283483fc7af8ff2b4ea19663c2d5ca935e26 # v0.24.2 + with: + syft-version: v1.51.1 - name: Build a snapshot and verify every artifact run: hack/verify-release-artifacts.sh snapshot + - name: Compare source container metadata and frontend assets + run: hack/check-container-equivalence.sh + - name: Exercise Linux package install, upgrade, shutdown and certificate ownership + env: + GH_TOKEN: ${{ github.token }} + run: hack/check-package-lifecycle.sh + - name: Rebuild the same commit twice in independent checkouts + run: hack/check-reproducible.sh swagger-codegen: name: "Check for uncommitted changes through Swagger Codegen Changes." @@ -199,9 +212,9 @@ jobs: os: [ubuntu-latest] steps: - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }} - uses: actions/setup-go@v7 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version: ${{ matrix.go-version }} - name: Read .nvmrc @@ -210,7 +223,7 @@ jobs: - name: Enable Corepack run: corepack enable - name: Setup Node - uses: actions/setup-node@v6 + uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.0.0 with: node-version: ${{ env.NVMRC }} cache: "yarn" @@ -256,10 +269,10 @@ jobs: steps: # Clone Console Repo - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 # To build minio image, we need to clone the repository first - name: Clone github.com/minio/minio - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: repository: minio/minio path: "minio_repository" @@ -278,11 +291,11 @@ jobs: fi cd $GITHUB_WORKSPACE; - name: Set up Go ${{ matrix.go-version }} on ${{ runner.os }} - uses: actions/setup-go@v7 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version: ${{ matrix.go-version }} id: go-minio - - uses: actions/cache@v5 + - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 id: assets-cache name: Assets Cache with: @@ -305,7 +318,7 @@ jobs: cd $GITHUB_WORKSPACE cp $GITHUB_WORKSPACE/minio_repository/minio . - - uses: actions/cache/save@v5 + - uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 # skip minio binary cache if: false id: minio-latest-cache @@ -315,7 +328,7 @@ jobs: ./minio key: ${{ runner.os }}-minio-latest-${{ github.run_id }} - - uses: actions/upload-artifact@v7 + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 # skip minio binary upload if: false with: @@ -338,20 +351,20 @@ jobs: os: [ubuntu-latest] steps: - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }} - uses: actions/setup-go@v7 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version: ${{ matrix.go-version }} id: go - - uses: actions/cache@v5 + - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 name: Console Binary Cache with: path: | ./console key: ${{ runner.os }}-binary-${{ github.run_id }} - - uses: actions/cache@v5 + - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 id: assets-cache name: Assets Cache with: @@ -377,24 +390,24 @@ jobs: os: [ubuntu-latest] steps: - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Read .nvmrc id: node_version run: echo "$(cat .nvmrc)" && echo "NVMRC=$(cat .nvmrc)" >> $GITHUB_ENV - name: Enable Corepack run: corepack enable - - uses: actions/setup-node@v6 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.0.0 with: node-version: ${{ env.NVMRC }} cache: "yarn" cache-dependency-path: web-app/yarn.lock - - name: Install MinIO JS - working-directory: ./ + - name: Install locked browser dependencies + working-directory: ./web-app continue-on-error: false run: | - yarn add minio + yarn install --immutable - - uses: actions/cache@v5 + - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 name: Console Binary Cache with: path: | @@ -410,22 +423,15 @@ jobs: run: | (CONSOLE_SUBPATH=/console/subpath ./console server ) & (make test-initialize-minio-nginx) - - name: Setup firefox - if: false - id: setup-firefox - uses: browser-actions/setup-firefox@v1 - with: - firefox-version: ${{ env.FIREFOX_VERSION }} - - - name: Install TestCafe - run: npm install testcafe@${{ env.TESTCAFE_VERSION }} + - name: Install the pinned and checksum-verified Firefox + run: bash hack/install-ci-firefox.sh - name: Run TestCafe Tests # Evidence for the next flake: a screenshot per failed test, uploaded per job and attempt. - run: npx testcafe "firefox:headless" web-app/tests/subpath-nginx/ -q --skip-js-errors --screenshots 'path=testcafe-screenshots,takeOnFails=true,pathPattern=${FIXTURE}/${TEST}.png' + run: ./web-app/node_modules/.bin/testcafe "firefox:headless" web-app/tests/subpath-nginx/ -q --skip-js-errors --screenshots 'path=testcafe-screenshots,takeOnFails=true,pathPattern=${FIXTURE}/${TEST}.png' - name: Upload TestCafe screenshots if: failure() - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: testcafe-${{ github.job }}-attempt-${{ github.run_attempt }} path: testcafe-screenshots @@ -448,24 +454,24 @@ jobs: os: [ubuntu-latest] steps: - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Read .nvmrc id: node_version run: echo "$(cat .nvmrc)" && echo "NVMRC=$(cat .nvmrc)" >> $GITHUB_ENV - name: Enable Corepack run: corepack enable - - uses: actions/setup-node@v6 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.0.0 with: node-version: ${{ env.NVMRC }} cache: "yarn" cache-dependency-path: web-app/yarn.lock - - name: Install MinIO JS - working-directory: ./ + - name: Install locked browser dependencies + working-directory: ./web-app continue-on-error: false run: | - yarn add minio + yarn install --immutable - - uses: actions/cache@v5 + - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 name: Console Binary Cache with: path: | @@ -481,22 +487,15 @@ jobs: run: | (./console server) & (make initialize-permissions) - - name: Setup firefox - if: false - id: setup-firefox - uses: browser-actions/setup-firefox@v1 - with: - firefox-version: ${{ env.FIREFOX_VERSION }} - - - name: Install TestCafe - run: npm install testcafe@${{ env.TESTCAFE_VERSION }} + - name: Install the pinned and checksum-verified Firefox + run: bash hack/install-ci-firefox.sh - name: Run TestCafe Tests # Evidence for the next flake: a screenshot per failed test, uploaded per job and attempt. - run: npx testcafe "firefox:headless" web-app/tests/permissions-1/ -q --skip-js-errors --screenshots 'path=testcafe-screenshots,takeOnFails=true,pathPattern=${FIXTURE}/${TEST}.png' + run: ./web-app/node_modules/.bin/testcafe "firefox:headless" web-app/tests/permissions-1/ -q --skip-js-errors --screenshots 'path=testcafe-screenshots,takeOnFails=true,pathPattern=${FIXTURE}/${TEST}.png' - name: Upload TestCafe screenshots if: failure() - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: testcafe-${{ github.job }}-attempt-${{ github.run_attempt }} path: testcafe-screenshots @@ -518,23 +517,23 @@ jobs: os: [ubuntu-latest] steps: - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Read .nvmrc id: node_version run: echo "$(cat .nvmrc)" && echo "NVMRC=$(cat .nvmrc)" >> $GITHUB_ENV - name: Enable Corepack run: corepack enable - - uses: actions/setup-node@v6 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.0.0 with: node-version: ${{ env.NVMRC }} cache: "yarn" cache-dependency-path: web-app/yarn.lock - - name: Install MinIO JS - working-directory: ./ + - name: Install locked browser dependencies + working-directory: ./web-app continue-on-error: false run: | - yarn add minio - - uses: actions/cache@v5 + yarn install --immutable + - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 name: Console Binary Cache with: path: | @@ -550,22 +549,15 @@ jobs: run: | (./console server) & (make initialize-permissions) - - name: Setup firefox - if: false - id: setup-firefox - uses: browser-actions/setup-firefox@v1 - with: - firefox-version: ${{ env.FIREFOX_VERSION }} - - - name: Install TestCafe - run: npm install testcafe@${{ env.TESTCAFE_VERSION }} + - name: Install the pinned and checksum-verified Firefox + run: bash hack/install-ci-firefox.sh - name: Run TestCafe Tests # Evidence for the next flake: a screenshot per failed test, uploaded per job and attempt. - run: npx testcafe "firefox:headless" web-app/tests/permissions-2/ -q --skip-js-errors -c 1 --screenshots 'path=testcafe-screenshots,takeOnFails=true,pathPattern=${FIXTURE}/${TEST}.png' + run: ./web-app/node_modules/.bin/testcafe "firefox:headless" web-app/tests/permissions-2/ -q --skip-js-errors -c 1 --screenshots 'path=testcafe-screenshots,takeOnFails=true,pathPattern=${FIXTURE}/${TEST}.png' - name: Upload TestCafe screenshots if: failure() - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: testcafe-${{ github.job }}-attempt-${{ github.run_attempt }} path: testcafe-screenshots @@ -587,23 +579,23 @@ jobs: os: [ubuntu-latest] steps: - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Read .nvmrc id: node_version run: echo "$(cat .nvmrc)" && echo "NVMRC=$(cat .nvmrc)" >> $GITHUB_ENV - name: Enable Corepack run: corepack enable - - uses: actions/setup-node@v6 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.0.0 with: node-version: ${{ env.NVMRC }} cache: "yarn" cache-dependency-path: web-app/yarn.lock - - name: Install MinIO JS - working-directory: ./ + - name: Install locked browser dependencies + working-directory: ./web-app continue-on-error: false run: | - yarn add minio - - uses: actions/cache@v5 + yarn install --immutable + - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 name: Console Binary Cache with: path: | @@ -619,22 +611,15 @@ jobs: run: | (./console server) & (make initialize-permissions) - - name: Setup firefox - if: false - id: setup-firefox - uses: browser-actions/setup-firefox@v1 - with: - firefox-version: ${{ env.FIREFOX_VERSION }} - - - name: Install TestCafe - run: npm install testcafe@${{ env.TESTCAFE_VERSION }} + - name: Install the pinned and checksum-verified Firefox + run: bash hack/install-ci-firefox.sh - name: Run TestCafe Tests # Evidence for the next flake: a screenshot per failed test, uploaded per job and attempt. - run: npx testcafe "firefox:headless" web-app/tests/permissions-3/ -q --skip-js-errors -c 1 --screenshots 'path=testcafe-screenshots,takeOnFails=true,pathPattern=${FIXTURE}/${TEST}.png' + run: ./web-app/node_modules/.bin/testcafe "firefox:headless" web-app/tests/permissions-3/ -q --skip-js-errors -c 1 --screenshots 'path=testcafe-screenshots,takeOnFails=true,pathPattern=${FIXTURE}/${TEST}.png' - name: Upload TestCafe screenshots if: failure() - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: testcafe-${{ github.job }}-attempt-${{ github.run_attempt }} path: testcafe-screenshots @@ -656,23 +641,23 @@ jobs: os: [ubuntu-latest] steps: - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Read .nvmrc id: node_version run: echo "$(cat .nvmrc)" && echo "NVMRC=$(cat .nvmrc)" >> $GITHUB_ENV - name: Enable Corepack run: corepack enable - - uses: actions/setup-node@v6 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.0.0 with: node-version: ${{ env.NVMRC }} cache: "yarn" cache-dependency-path: web-app/yarn.lock - - name: Install MinIO JS - working-directory: ./ + - name: Install locked browser dependencies + working-directory: ./web-app continue-on-error: false run: | - yarn add minio - - uses: actions/cache@v5 + yarn install --immutable + - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 name: Console Binary Cache with: path: | @@ -688,23 +673,16 @@ jobs: run: | (./console server) & (make initialize-permissions) - - name: Setup firefox - if: false - id: setup-firefox - uses: browser-actions/setup-firefox@v1 - with: - firefox-version: ${{ env.FIREFOX_VERSION }} - - - name: Install TestCafe - run: npm install testcafe@${{ env.TESTCAFE_VERSION }} + - name: Install the pinned and checksum-verified Firefox + run: bash hack/install-ci-firefox.sh - name: Run TestCafe Tests timeout-minutes: 10 # Evidence for the next flake: a screenshot per failed test, uploaded per job and attempt. - run: npx testcafe "firefox:headless" web-app/tests/permissions-4/ --skip-js-errors --screenshots 'path=testcafe-screenshots,takeOnFails=true,pathPattern=${FIXTURE}/${TEST}.png' + run: ./web-app/node_modules/.bin/testcafe "firefox:headless" web-app/tests/permissions-4/ --skip-js-errors --screenshots 'path=testcafe-screenshots,takeOnFails=true,pathPattern=${FIXTURE}/${TEST}.png' - name: Upload TestCafe screenshots if: failure() - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: testcafe-${{ github.job }}-attempt-${{ github.run_attempt }} path: testcafe-screenshots @@ -721,23 +699,23 @@ jobs: os: [ubuntu-latest] steps: - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Read .nvmrc id: node_version run: echo "$(cat .nvmrc)" && echo "NVMRC=$(cat .nvmrc)" >> $GITHUB_ENV - name: Enable Corepack run: corepack enable - - uses: actions/setup-node@v6 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.0.0 with: node-version: ${{ env.NVMRC }} cache: "yarn" cache-dependency-path: web-app/yarn.lock - - name: Install MinIO JS - working-directory: ./ + - name: Install locked browser dependencies + working-directory: ./web-app continue-on-error: false run: | - yarn add minio - - uses: actions/cache@v5 + yarn install --immutable + - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 name: Console Binary Cache with: path: | @@ -753,23 +731,16 @@ jobs: run: | (./console server) & (make initialize-permissions) - - name: Setup firefox - if: false - id: setup-firefox - uses: browser-actions/setup-firefox@v1 - with: - firefox-version: ${{ env.FIREFOX_VERSION }} - - - name: Install TestCafe - run: npm install testcafe@${{ env.TESTCAFE_VERSION }} + - name: Install the pinned and checksum-verified Firefox + run: bash hack/install-ci-firefox.sh - name: Run TestCafe Tests timeout-minutes: 5 # Evidence for the next flake: a screenshot per failed test, uploaded per job and attempt. - run: npx testcafe "firefox:headless" web-app/tests/permissions-5/ --skip-js-errors --screenshots 'path=testcafe-screenshots,takeOnFails=true,pathPattern=${FIXTURE}/${TEST}.png' + run: ./web-app/node_modules/.bin/testcafe "firefox:headless" web-app/tests/permissions-5/ --skip-js-errors --screenshots 'path=testcafe-screenshots,takeOnFails=true,pathPattern=${FIXTURE}/${TEST}.png' - name: Upload TestCafe screenshots if: failure() - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: testcafe-${{ github.job }}-attempt-${{ github.run_attempt }} path: testcafe-screenshots @@ -786,23 +757,23 @@ jobs: os: [ubuntu-latest] steps: - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Read .nvmrc id: node_version run: echo "$(cat .nvmrc)" && echo "NVMRC=$(cat .nvmrc)" >> $GITHUB_ENV - name: Enable Corepack run: corepack enable - - uses: actions/setup-node@v6 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.0.0 with: node-version: ${{ env.NVMRC }} cache: "yarn" cache-dependency-path: web-app/yarn.lock - - name: Install MinIO JS - working-directory: ./ + - name: Install locked browser dependencies + working-directory: ./web-app continue-on-error: false run: | - yarn add minio - - uses: actions/cache@v5 + yarn install --immutable + - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 name: Console Binary Cache with: path: | @@ -818,23 +789,16 @@ jobs: run: | (./console server) & (make initialize-permissions) - - name: Setup firefox - if: false - id: setup-firefox - uses: browser-actions/setup-firefox@v1 - with: - firefox-version: ${{ env.FIREFOX_VERSION }} - - - name: Install TestCafe - run: npm install testcafe@${{ env.TESTCAFE_VERSION }} + - name: Install the pinned and checksum-verified Firefox + run: bash hack/install-ci-firefox.sh - name: Run TestCafe Tests timeout-minutes: 5 # Evidence for the next flake: a screenshot per failed test, uploaded per job and attempt. - run: npx testcafe "firefox:headless" web-app/tests/permissions-6/ --skip-js-errors --screenshots 'path=testcafe-screenshots,takeOnFails=true,pathPattern=${FIXTURE}/${TEST}.png' + run: ./web-app/node_modules/.bin/testcafe "firefox:headless" web-app/tests/permissions-6/ --skip-js-errors --screenshots 'path=testcafe-screenshots,takeOnFails=true,pathPattern=${FIXTURE}/${TEST}.png' - name: Upload TestCafe screenshots if: failure() - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: testcafe-${{ github.job }}-attempt-${{ github.run_attempt }} path: testcafe-screenshots @@ -851,23 +815,23 @@ jobs: os: [ubuntu-latest] steps: - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Read .nvmrc id: node_version run: echo "$(cat .nvmrc)" && echo "NVMRC=$(cat .nvmrc)" >> $GITHUB_ENV - name: Enable Corepack run: corepack enable - - uses: actions/setup-node@v6 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.0.0 with: node-version: ${{ env.NVMRC }} cache: "yarn" cache-dependency-path: web-app/yarn.lock - - name: Install MinIO JS - working-directory: ./ + - name: Install locked browser dependencies + working-directory: ./web-app continue-on-error: false run: | - yarn add minio - - uses: actions/cache@v5 + yarn install --immutable + - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 name: Console Binary Cache with: path: | @@ -883,23 +847,16 @@ jobs: run: | (./console server) & (make initialize-permissions) - - name: Setup firefox - if: false - id: setup-firefox - uses: browser-actions/setup-firefox@v1 - with: - firefox-version: ${{ env.FIREFOX_VERSION }} - - - name: Install TestCafe - run: npm install testcafe@${{ env.TESTCAFE_VERSION }} + - name: Install the pinned and checksum-verified Firefox + run: bash hack/install-ci-firefox.sh - name: Run TestCafe Tests timeout-minutes: 10 # Evidence for the next flake: a screenshot per failed test, uploaded per job and attempt. - run: npx testcafe "firefox:headless" web-app/tests/permissions-7/ --skip-js-errors -c 1 --screenshots 'path=testcafe-screenshots,takeOnFails=true,pathPattern=${FIXTURE}/${TEST}.png' + run: ./web-app/node_modules/.bin/testcafe "firefox:headless" web-app/tests/permissions-7/ --skip-js-errors -c 1 --screenshots 'path=testcafe-screenshots,takeOnFails=true,pathPattern=${FIXTURE}/${TEST}.png' - name: Upload TestCafe screenshots if: failure() - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: testcafe-${{ github.job }}-attempt-${{ github.run_attempt }} path: testcafe-screenshots @@ -916,23 +873,23 @@ jobs: os: [ubuntu-latest] steps: - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Read .nvmrc id: node_version run: echo "$(cat .nvmrc)" && echo "NVMRC=$(cat .nvmrc)" >> $GITHUB_ENV - name: Enable Corepack run: corepack enable - - uses: actions/setup-node@v6 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.0.0 with: node-version: ${{ env.NVMRC }} cache: "yarn" cache-dependency-path: web-app/yarn.lock - - name: Install MinIO JS - working-directory: ./ + - name: Install locked browser dependencies + working-directory: ./web-app continue-on-error: false run: | - yarn add minio - - uses: actions/cache@v5 + yarn install --immutable + - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 name: Console Binary Cache with: path: | @@ -948,23 +905,16 @@ jobs: run: | (./console server) & (make initialize-permissions) - - name: Setup firefox - if: false - id: setup-firefox - uses: browser-actions/setup-firefox@v1 - with: - firefox-version: ${{ env.FIREFOX_VERSION }} - - - name: Install TestCafe - run: npm install testcafe@${{ env.TESTCAFE_VERSION }} + - name: Install the pinned and checksum-verified Firefox + run: bash hack/install-ci-firefox.sh - name: Run TestCafe Tests timeout-minutes: 5 # Evidence for the next flake: a screenshot per failed test, uploaded per job and attempt. - run: npx testcafe "firefox:headless" web-app/tests/permissions-8/ --skip-js-errors --screenshots 'path=testcafe-screenshots,takeOnFails=true,pathPattern=${FIXTURE}/${TEST}.png' + run: ./web-app/node_modules/.bin/testcafe "firefox:headless" web-app/tests/permissions-8/ --skip-js-errors --screenshots 'path=testcafe-screenshots,takeOnFails=true,pathPattern=${FIXTURE}/${TEST}.png' - name: Upload TestCafe screenshots if: failure() - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: testcafe-${{ github.job }}-attempt-${{ github.run_attempt }} path: testcafe-screenshots @@ -981,23 +931,23 @@ jobs: os: [ubuntu-latest] steps: - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Read .nvmrc id: node_version run: echo "$(cat .nvmrc)" && echo "NVMRC=$(cat .nvmrc)" >> $GITHUB_ENV - name: Enable Corepack run: corepack enable - - uses: actions/setup-node@v6 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.0.0 with: node-version: ${{ env.NVMRC }} cache: "yarn" cache-dependency-path: web-app/yarn.lock - - name: Install MinIO JS - working-directory: ./ + - name: Install locked browser dependencies + working-directory: ./web-app continue-on-error: false run: | - yarn add minio - - uses: actions/cache@v5 + yarn install --immutable + - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 name: Console Binary Cache with: path: | @@ -1013,22 +963,15 @@ jobs: run: | (./console server) & (make initialize-permissions) - - name: Setup firefox - if: false - id: setup-firefox - uses: browser-actions/setup-firefox@v1 - with: - firefox-version: ${{ env.FIREFOX_VERSION }} - - - name: Install TestCafe - run: npm install testcafe@${{ env.TESTCAFE_VERSION }} + - name: Install the pinned and checksum-verified Firefox + run: bash hack/install-ci-firefox.sh - name: Run TestCafe Tests # Evidence for the next flake: a screenshot per failed test, uploaded per job and attempt. - run: npx testcafe "firefox:headless" web-app/tests/permissions-A/ --skip-js-errors -c 1 --screenshots 'path=testcafe-screenshots,takeOnFails=true,pathPattern=${FIXTURE}/${TEST}.png' + run: ./web-app/node_modules/.bin/testcafe "firefox:headless" web-app/tests/permissions-A/ --skip-js-errors -c 1 --screenshots 'path=testcafe-screenshots,takeOnFails=true,pathPattern=${FIXTURE}/${TEST}.png' - name: Upload TestCafe screenshots if: failure() - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: testcafe-${{ github.job }}-attempt-${{ github.run_attempt }} path: testcafe-screenshots @@ -1049,23 +992,23 @@ jobs: os: [ubuntu-latest] steps: - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Read .nvmrc id: node_version run: echo "$(cat .nvmrc)" && echo "NVMRC=$(cat .nvmrc)" >> $GITHUB_ENV - name: Enable Corepack run: corepack enable - - uses: actions/setup-node@v6 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.0.0 with: node-version: ${{ env.NVMRC }} cache: "yarn" cache-dependency-path: web-app/yarn.lock - - name: Install MinIO JS - working-directory: ./ + - name: Install locked browser dependencies + working-directory: ./web-app continue-on-error: false run: | - yarn add minio - - uses: actions/cache@v5 + yarn install --immutable + - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 name: Console Binary Cache with: path: | @@ -1081,22 +1024,15 @@ jobs: run: | (./console server) & (make initialize-permissions) - - name: Setup firefox - if: false - id: setup-firefox - uses: browser-actions/setup-firefox@v1 - with: - firefox-version: ${{ env.FIREFOX_VERSION }} - - - name: Install TestCafe - run: npm install testcafe@${{ env.TESTCAFE_VERSION }} + - name: Install the pinned and checksum-verified Firefox + run: bash hack/install-ci-firefox.sh - name: Run TestCafe Tests # Evidence for the next flake: a screenshot per failed test, uploaded per job and attempt. - run: npx testcafe "firefox:headless" web-app/tests/permissions-B/ --skip-js-errors -c 1 --screenshots 'path=testcafe-screenshots,takeOnFails=true,pathPattern=${FIXTURE}/${TEST}.png' + run: ./web-app/node_modules/.bin/testcafe "firefox:headless" web-app/tests/permissions-B/ --skip-js-errors -c 1 --screenshots 'path=testcafe-screenshots,takeOnFails=true,pathPattern=${FIXTURE}/${TEST}.png' - name: Upload TestCafe screenshots if: failure() - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: testcafe-${{ github.job }}-attempt-${{ github.run_attempt }} path: testcafe-screenshots @@ -1119,10 +1055,10 @@ jobs: os: [ubuntu-latest] steps: - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }} - uses: actions/setup-go@v7 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version: ${{ matrix.go-version }} id: go @@ -1134,7 +1070,7 @@ jobs: run: | make test-pkg - - uses: actions/cache@v5 + - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 id: coverage-cache-pkg name: Coverage Cache Pkg with: @@ -1155,10 +1091,10 @@ jobs: os: [ubuntu-latest] steps: - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }} - uses: actions/setup-go@v7 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version: ${{ matrix.go-version }} id: go @@ -1170,7 +1106,7 @@ jobs: run: | make test - - uses: actions/cache@v5 + - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 id: coverage-cache-api name: Coverage Cache API with: @@ -1193,14 +1129,14 @@ jobs: steps: - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Set up Go ${{ matrix.go-version }} on ${{ runner.os }} - uses: actions/setup-go@v7 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version: ${{ matrix.go-version }} id: go - - uses: actions/cache@v5 + - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 name: Console Binary Cache with: path: | @@ -1220,7 +1156,7 @@ jobs: make test-integration MINIO_VERSION=$MINIO_VERSION TAG=$TAG; - - uses: actions/cache@v5 + - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 id: coverage-cache name: Coverage Cache with: @@ -1243,10 +1179,10 @@ jobs: steps: - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Set up Go ${{ matrix.go-version }} on ${{ runner.os }} - uses: actions/setup-go@v7 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version: ${{ matrix.go-version }} id: go @@ -1257,7 +1193,7 @@ jobs: echo $MINIO_VERSION; make test-replication MINIO_VERSION=$MINIO_VERSION; - - uses: actions/cache@v5 + - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 id: coverage-cache-replication name: Coverage Cache Replication with: @@ -1280,10 +1216,10 @@ jobs: steps: - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Set up Go ${{ matrix.go-version }} on ${{ runner.os }} - uses: actions/setup-go@v7 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version: ${{ matrix.go-version }} id: go @@ -1294,7 +1230,7 @@ jobs: echo $MINIO_VERSION; make test-sso-integration MINIO_VERSION=$MINIO_VERSION; - - uses: actions/cache@v5 + - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 id: coverage-cache-sso name: Coverage Cache SSO with: @@ -1317,19 +1253,19 @@ jobs: os: [ubuntu-latest] steps: - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }} - uses: actions/setup-go@v7 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version: ${{ matrix.go-version }} id: go - name: Check out gocovmerge as a nested repository - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 with: repository: wadey/gocovmerge path: gocovmerge - - uses: actions/cache@v5 + - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 id: coverage-cache name: Coverage Cache with: @@ -1337,7 +1273,7 @@ jobs: ./integration/coverage/ key: ${{ runner.os }}-coverage-2-${{ github.run_id }} - - uses: actions/cache@v5 + - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 id: coverage-cache-sso name: Coverage Cache SSO with: @@ -1345,7 +1281,7 @@ jobs: ./sso-integration/coverage/ key: ${{ runner.os }}-sso-coverage-2-${{ github.run_id }} - - uses: actions/cache@v5 + - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 id: coverage-cache-replication name: Coverage Cache Replication with: @@ -1353,7 +1289,7 @@ jobs: ./replication/coverage/ key: ${{ runner.os }}-replication-coverage-2-${{ github.run_id }} - - uses: actions/cache@v5 + - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 id: coverage-cache-api name: Coverage Cache API with: @@ -1361,7 +1297,7 @@ jobs: ./api/coverage/ key: ${{ runner.os }}-coverage-api-2-${{ github.run_id }} - - uses: actions/cache@v5 + - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 id: coverage-cache-pkg name: Coverage Cache Pkg with: @@ -1404,7 +1340,7 @@ jobs: # To save our all.out and all-coverage.html file into an artifact. # By default, GitHub stores build logs and artifacts for 90 days. - - uses: actions/upload-artifact@v7 + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: coverage-artifact path: | @@ -1421,18 +1357,18 @@ jobs: os: [ubuntu-latest] steps: - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Read .nvmrc id: node_version run: echo "$(cat .nvmrc)" && echo "NVMRC=$(cat .nvmrc)" >> $GITHUB_ENV - name: Enable Corepack run: corepack enable - - uses: actions/setup-node@v6 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.0.0 with: node-version: ${{ env.NVMRC }} cache: "yarn" cache-dependency-path: web-app/yarn.lock - - uses: actions/cache@v5 + - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 id: assets-cache-istanbul-coverage name: Assets Cache Istanbul Coverage with: @@ -1464,20 +1400,20 @@ jobs: os: [ubuntu-latest] steps: - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }} - uses: actions/setup-go@v7 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version: ${{ matrix.go-version }} id: go - - uses: actions/cache@v5 + - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 name: Console Binary Cache Istanbul Coverage with: path: | ./console key: ${{ runner.os }}-binary-istanbul-coverage-${{ github.run_id }} - - uses: actions/cache@v5 + - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 id: assets-cache-istanbul-coverage name: Assets Cache Istanbul Coverage with: @@ -1504,10 +1440,10 @@ jobs: os: [ubuntu-latest] steps: - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }} - uses: actions/setup-go@v7 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version: ${{ matrix.go-version }} id: go @@ -1532,9 +1468,9 @@ jobs: os: [ubuntu-latest] steps: - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }} - uses: actions/setup-go@v7 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version: ${{ matrix.go-version }} id: go @@ -1559,10 +1495,10 @@ jobs: os: [ubuntu-latest] steps: - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }} - uses: actions/setup-go@v7 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version: ${{ matrix.go-version }} id: go @@ -1587,10 +1523,10 @@ jobs: os: [ubuntu-latest] steps: - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }} - uses: actions/setup-go@v7 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version: ${{ matrix.go-version }} id: go @@ -1615,10 +1551,10 @@ jobs: os: [ubuntu-latest] steps: - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Set up Go ${{ matrix.go-version }} on ${{ matrix.os }} - uses: actions/setup-go@v7 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version: ${{ matrix.go-version }} id: go @@ -1636,13 +1572,13 @@ jobs: timeout-minutes: 60 runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Read .nvmrc id: node_version run: echo "$(cat .nvmrc)" && echo "NVMRC=$(cat .nvmrc)" >> $GITHUB_ENV - name: Enable Corepack run: corepack enable - - uses: actions/setup-node@v6 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.0.0 with: node-version: ${{ env.NVMRC }} cache: "yarn" @@ -1656,7 +1592,7 @@ jobs: working-directory: web-app run: yarn exec playwright install --with-deps chromium - - uses: actions/cache@v5 + - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 name: Console Binary Cache Istanbul Coverage with: path: | diff --git a/.github/workflows/promote-image.yaml b/.github/workflows/promote-image.yaml new file mode 100644 index 0000000000..cf57d58c3f --- /dev/null +++ b/.github/workflows/promote-image.yaml @@ -0,0 +1,66 @@ +name: Promote published image +on: + release: + types: [published] +permissions: + contents: read +concurrency: + group: silo-console-latest + cancel-in-progress: false +jobs: + promote: + if: ${{ !github.event.release.draft && !github.event.release.prerelease }} + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + attestations: read + steps: + - uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2 + with: + cosign-release: v3.1.3 + - uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0 + with: + version: v0.36.1 + - uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Verify the published version before advancing latest + env: + GH_TOKEN: ${{ github.token }} + TAG: ${{ github.event.release.tag_name }} + run: | + set -euo pipefail + [[ "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] + release=$(gh api "repos/${GITHUB_REPOSITORY}/releases/tags/$TAG") + jq -e '.draft == false and .prerelease == false' <<<"$release" + latest=$(gh api "repos/${GITHUB_REPOSITORY}/releases/latest" --jq .tag_name) + if [ "$TAG" != "$latest" ]; then + echo "This is not the current GitHub release; latest is unchanged." >> "$GITHUB_STEP_SUMMARY" + exit 0 + fi + image="ghcr.io/${GITHUB_REPOSITORY}" + identity="https://github.com/${GITHUB_REPOSITORY}/.github/workflows/release.yaml@refs/tags/$TAG" + issuer="https://token.actions.githubusercontent.com" + digest=$(docker buildx imagetools inspect "$image:$TAG" --format '{{.Manifest.Digest}}') + [[ "$digest" =~ ^sha256:[0-9a-f]{64}$ ]] + cosign verify --certificate-identity "$identity" --certificate-oidc-issuer "$issuer" "$image@$digest" + cosign verify-attestation --type spdxjson --certificate-identity "$identity" --certificate-oidc-issuer "$issuer" "$image@$digest" + gh attestation verify "oci://$image@$digest" --repo "$GITHUB_REPOSITORY" + mkdir verification + gh release download "$TAG" --repo "$GITHUB_REPOSITORY" --dir verification --pattern '*_checksums.txt*' + for checksum in verification/*_checksums.txt; do + cosign verify-blob --bundle "${checksum}.sigstore.json" --certificate-identity "$identity" --certificate-oidc-issuer "$issuer" "$checksum" + gh attestation verify "$checksum" --repo "$GITHUB_REPOSITORY" + done + # Empty Docker credentials ensure public access is actually tested. + anonymous_config=$(mktemp -d) + DOCKER_CONFIG="$anonymous_config" docker manifest inspect "$image@$digest" >/dev/null + rm -rf "$anonymous_config" + # Recheck after verification, in case another release was published. + test "$TAG" = "$(gh api "repos/${GITHUB_REPOSITORY}/releases/latest" --jq .tag_name)" + docker buildx imagetools create --tag "$image:latest" "$image@$digest" + test "$digest" = "$(docker buildx imagetools inspect "$image:latest" --format '{{.Manifest.Digest}}')" + echo "Public latest now points to the verified $TAG image: $digest" >> "$GITHUB_STEP_SUMMARY" diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index c97f37360c..c86540db0b 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -15,6 +15,8 @@ jobs: contents: write packages: write actions: read + id-token: write + attestations: write steps: - name: Checkout uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 @@ -116,6 +118,27 @@ jobs: with: version: v0.36.1 + - name: Install Cosign + uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2 + with: + cosign-release: v3.1.3 + + - name: Install Syft + uses: anchore/sbom-action/download-syft@3ad7283483fc7af8ff2b4ea19663c2d5ca935e26 # v0.24.2 + with: + syft-version: v1.51.1 + + - name: Refuse to overwrite a published release + env: + GH_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + if release=$(gh api "repos/${GITHUB_REPOSITORY}/releases/tags/${GITHUB_REF_NAME}"); then + jq -e '.draft == true' <<<"$release" + else + jq -e '.status == "404"' <<<"$release" + fi + - name: Run GoReleaser uses: goreleaser/goreleaser-action@f06c13b6b1a9625abc9e6e439d9c05a8f2190e94 # v7.2.3 with: @@ -123,3 +146,50 @@ jobs: args: release --clean env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Verify checksum signatures and resolve the immutable image + id: image + env: + GH_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + identity="https://github.com/${GITHUB_REPOSITORY}/.github/workflows/release.yaml@${GITHUB_REF}" + issuer="https://token.actions.githubusercontent.com" + for checksum in dist/*_checksums.txt; do + cosign verify-blob --bundle "${checksum}.sigstore.json" --certificate-identity "$identity" --certificate-oidc-issuer "$issuer" "$checksum" + done + image="ghcr.io/${GITHUB_REPOSITORY}" + digest=$(docker buildx imagetools inspect "$image:${GITHUB_REF_NAME}" --format '{{.Manifest.Digest}}') + [[ "$digest" =~ ^sha256:[0-9a-f]{64}$ ]] + cosign verify --certificate-identity "$identity" --certificate-oidc-issuer "$issuer" "$image@$digest" + echo "name=$image" >> "$GITHUB_OUTPUT" + echo "digest=$digest" >> "$GITHUB_OUTPUT" + syft scan "registry:$image@$digest" -o spdx-json=dist/image.spdx.json --quiet + cosign attest --yes --type spdxjson --predicate dist/image.spdx.json "$image@$digest" + cosign verify-attestation --type spdxjson --certificate-identity "$identity" --certificate-oidc-issuer "$issuer" "$image@$digest" + gh release upload "$GITHUB_REF_NAME" dist/image.spdx.json --clobber + + - name: Attest the checksum manifest + uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2 + with: + subject-path: dist/*_checksums.txt + + - name: Attest the OCI image + uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2 + with: + subject-name: ${{ steps.image.outputs.name }} + subject-digest: ${{ steps.image.outputs.digest }} + push-to-registry: true + + - name: Verify provenance before the draft is ready to publish + env: + GH_TOKEN: ${{ github.token }} + IMAGE: ${{ steps.image.outputs.name }} + DIGEST: ${{ steps.image.outputs.digest }} + run: | + set -euo pipefail + for checksum in dist/*_checksums.txt; do + gh attestation verify "$checksum" --repo "$GITHUB_REPOSITORY" + done + gh attestation verify "oci://$IMAGE@$DIGEST" --repo "$GITHUB_REPOSITORY" + echo "Draft assets, signatures, SBOMs and provenance verified. Publishing this draft enables the separate latest-image promotion gate." >> "$GITHUB_STEP_SUMMARY" diff --git a/.github/workflows/vulncheck.yaml b/.github/workflows/vulncheck.yaml index 64c0b6f1f6..5473d8f05b 100644 --- a/.github/workflows/vulncheck.yaml +++ b/.github/workflows/vulncheck.yaml @@ -19,9 +19,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code into the Go module directory - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Set up Go - uses: actions/setup-go@v7 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version-file: go.mod check-latest: true @@ -41,11 +41,11 @@ jobs: os: [ubuntu-latest] steps: - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 - name: Read .nvmrc id: node_version run: echo "$(cat .nvmrc)" && echo "NVMRC=$(cat .nvmrc)" >> $GITHUB_ENV - - uses: actions/setup-node@v6 + - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.0.0 with: node-version: ${{ env.NVMRC }} - name: Enable Corepack diff --git a/.goreleaser.yml b/.goreleaser.yml index 7395d94f4d..a0d35aeae6 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -7,8 +7,9 @@ release: github: owner: pgsty name: silo-console - # Keep the release private until the maintainer reviews its notes and assets. + # Keep GitHub release metadata in draft until verification is complete. draft: true + replace_existing_artifacts: true prerelease: false extra_files: - glob: LICENSE @@ -19,6 +20,7 @@ before: hooks: - go mod download - go mod verify + - python3 hack/normalize-package-inputs.py builds: - goos: @@ -38,12 +40,13 @@ builds: goarch: arm env: - CGO_ENABLED=0 + mod_timestamp: "{{ .CommitTimestamp }}" main: ./cmd/console/ flags: - -trimpath - --tags=kqueue,operator ldflags: - - -s -w -X github.com/minio/console/pkg.ReleaseTag={{.Tag}} -X github.com/minio/console/pkg.CommitID={{.FullCommit}} -X github.com/minio/console/pkg.Version={{.Version}} -X github.com/minio/console/pkg.ShortCommitID={{.ShortCommit}} -X github.com/minio/console/pkg.ReleaseTime={{.Date}} + - -s -w -X github.com/minio/console/pkg.ReleaseTag={{.Tag}} -X github.com/minio/console/pkg.CommitID={{.FullCommit}} -X github.com/minio/console/pkg.Version={{.Version}} -X github.com/minio/console/pkg.ShortCommitID={{.ShortCommit}} -X github.com/minio/console/pkg.ReleaseTime={{.CommitDate}} archives: # Bare executables keep their historical asset names; each executable also @@ -59,9 +62,12 @@ archives: - goos: windows formats: ["zip"] files: - - LICENSE - - NOTICE - - CREDITS + - src: LICENSE + info: { owner: root, group: root, mode: 0644, mtime: "{{ .CommitDate }}" } + - src: NOTICE + info: { owner: root, group: root, mode: 0644, mtime: "{{ .CommitDate }}" } + - src: CREDITS + info: { owner: root, group: root, mode: 0644, mtime: "{{ .CommitDate }}" } checksum: name_template: "{{ .ProjectName }}_{{ .Version }}_checksums.txt" @@ -82,7 +88,8 @@ changelog: - "Merge branch" nfpms: - - vendor: PGSTY + - mtime: "{{ .CommitDate }}" + vendor: PGSTY homepage: https://silo.pgsty.com maintainer: "Ruohang Feng (@Vonng) " description: SILO object storage console, community-maintained MinIO Console fork. @@ -98,24 +105,34 @@ nfpms: - src: LICENSE dst: /usr/share/licenses/silo-console/LICENSE file_info: + mtime: "{{ .CommitDate }}" mode: 0644 - src: NOTICE dst: /usr/share/licenses/silo-console/NOTICE file_info: + mtime: "{{ .CommitDate }}" mode: 0644 - src: CREDITS dst: /usr/share/doc/silo-console/CREDITS file_info: + mtime: "{{ .CommitDate }}" + mode: 0644 + - src: systemd/README.md + dst: /usr/share/doc/silo-console/service.md + file_info: + mtime: "{{ .CommitDate }}" mode: 0644 - src: packaging/debian/copyright dst: /usr/share/doc/silo-console/copyright packager: deb file_info: + mtime: "{{ .CommitDate }}" mode: 0644 # DEB/RPM packages retain the compatibility unit name, see systemd/README.md - src: systemd/console.service dst: /etc/systemd/system/minio-console.service file_info: + mtime: "{{ .CommitDate }}" mode: 0644 owner: root group: root @@ -123,11 +140,39 @@ nfpms: dst: /etc/default/console type: config|noreplace file_info: + mtime: "{{ .CommitDate }}" mode: 0600 owner: root group: root + - dst: /var/lib/silo-console + type: dir + file_info: + mtime: "{{ .CommitDate }}" + mode: 0750 + owner: console-user + group: console-user + - dst: /etc/silo-console/certs/CAs + type: dir + file_info: + mtime: "{{ .CommitDate }}" + mode: 0750 + owner: root + group: console-user + # Stock Alpine has no systemd. A single APK account-creation hook also + # avoids nFPM's nondeterministic map iteration for multiple APK scripts. scripts: preinstall: systemd/preinstall.sh + overrides: + deb: + scripts: + postinstall: systemd/reload.sh + postremove: systemd/reload.sh + preremove: systemd/preremove.sh + rpm: + scripts: + postinstall: systemd/reload.sh + postremove: systemd/reload.sh + preremove: systemd/preremove.sh rpm: group: Applications/File compression: gzip:9 @@ -147,9 +192,9 @@ dockers_v2: - linux/arm64 tags: - "{{ if .IsSnapshot }}snapshot-{{ .ShortCommit }}{{ else }}{{ .Tag }}{{ end }}" - - "{{ if not .IsSnapshot }}latest{{ end }}" build_args: TAG: "{{ .Tag }}" + SOURCE_DATE_EPOCH: "{{ .CommitTimestamp }}" extra_files: - LICENSE - NOTICE @@ -160,7 +205,7 @@ dockers_v2: "org.opencontainers.image.name": "{{.ProjectName}}" "org.opencontainers.image.title": "{{.ProjectName}}" "org.opencontainers.image.description": "The SILO object storage console; AGPL-3.0-or-later, license and attribution in /usr/share/licenses/silo-console" - "org.opencontainers.image.created": "{{.Date}}" + "org.opencontainers.image.created": "{{.CommitDate}}" "org.opencontainers.image.revision": "{{.FullCommit}}" "org.opencontainers.image.version": "{{ if .IsSnapshot }}{{ .Version }}{{ else }}{{ .Tag }}{{ end }}" "org.opencontainers.image.url": "https://github.com/pgsty/silo-console" @@ -175,7 +220,7 @@ dockers_v2: "org.opencontainers.image.name": "{{.ProjectName}}" "org.opencontainers.image.title": "{{.ProjectName}}" "org.opencontainers.image.description": "The SILO object storage console; AGPL-3.0-or-later, license and attribution in /usr/share/licenses/silo-console" - "org.opencontainers.image.created": "{{.Date}}" + "org.opencontainers.image.created": "{{.CommitDate}}" "org.opencontainers.image.revision": "{{.FullCommit}}" "org.opencontainers.image.version": "{{ if .IsSnapshot }}{{ .Version }}{{ else }}{{ .Tag }}{{ end }}" "org.opencontainers.image.url": "https://github.com/pgsty/silo-console" @@ -184,3 +229,38 @@ dockers_v2: "org.opencontainers.image.licenses": "AGPL-3.0-or-later" "org.opencontainers.image.base.name": "scratch" "io.pgsty.silo-console.source": "{{ if .IsSnapshot }}https://github.com/pgsty/silo-console/commit/{{ .FullCommit }}{{ else }}https://github.com/pgsty/silo-console/tree/{{ .Tag }}{{ end }}" + +# Keyless identities bind the release workflow and tag; no signing key is stored. +signs: + - cmd: cosign + artifacts: checksum + signature: "${artifact}.sigstore.json" + args: ["sign-blob", "--yes", "--bundle", "${signature}", "${artifact}"] + +docker_signs: + - cmd: cosign + artifacts: all + args: ["sign", "--yes", "${artifact}"] + +sboms: + - id: binary-sbom + artifacts: binary + ids: [binaries] + cmd: bash + args: ["../hack/generate-sbom.sh", "${artifact}", "${document}"] + documents: ["{{ .ProjectName }}-{{ .Os }}-{{ .Arch }}.spdx.json"] + - id: package-sbom + artifacts: package + cmd: bash + args: ["../hack/generate-sbom.sh", "${artifact}", "${document}"] + documents: ["${artifact}.spdx.json"] + + - id: source-sbom + artifacts: source + cmd: bash + args: ["../hack/generate-sbom.sh", "${artifact}", "${document}"] + documents: ["${artifact}.spdx.json"] + +source: + enabled: true + name_template: "{{ .ProjectName }}-{{ .Version }}-source" diff --git a/.nvmrc b/.nvmrc index cabf43b5dd..df6ae3370f 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -24 \ No newline at end of file +24.21.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a71df4ad0..91044429f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,17 @@ - **Breaking authorization change:** uses `admin:ChangeMyPassword` for the Change Password button and session capability; user creation remains governed by `admin:CreateUser`. With the matching Server, a saved CreateUser deny no longer locks the caller's password, and a ChangeMyPassword deny now locks it. Preserve the old combined restriction by denying both actions before upgrading. The updated built-in `readonly` also permits self-service password changes and no longer overrides a separate CreateUser Allow; saved policy overrides retain their old statements. Deploy Server, silo-pkg and Console together. See the [migration guide](https://github.com/pgsty/silo/blob/420340bc142b7dec00c26c28dd78102e3ed9d0f3/docs/iam/password-permissions.md) for affected policies, mixed-version behavior and rollback limits. This change is independent of the SDK update. - Pins upstream minio-go to `78bfa91607c2`, including streaming Content-Type signing and RDMA TLS trust fixes, and updates the maintained package/client dependency pins. The upstream region-whitespace fix (#2274) remains pending. -- Updates knip's indirect smol-toml dependency to 1.7.1 for CVE-2026-85730. +- Updates knip's indirect smol-toml dependency to 1.8.0, retaining the fix for CVE-2026-85730. +- Stream multi-selection ZIP downloads with cancellation, duplicate protection, + and native browser downloads when a file writer is unavailable. +- Recover from invalid routes and rendering errors without clearing preferences. +- Finish remaining screen labels and localize icon controls, sign-out and keyboard tooltips. +- Lock CI Actions and test tools; make release timestamps and package metadata deterministic. +- Generate signed checksums, SBOMs and provenance; promote `latest` only after a + published release passes signature, provenance and anonymous-access checks. +- Bound systemd shutdown and define service state, certificate ownership and hardening. +- Warn before the packaged certificate-directory transition; preserve old keys + and document retaining the previous path through `CONSOLE_OPTS` before restart. ## Release v2.4.0 diff --git a/Dockerfile b/Dockerfile index 18cd90ff12..9d8060e641 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,46 +1,49 @@ -ARG GO_VERSION=1.27.1 -ARG NODE_VERSION=24 -FROM node:${NODE_VERSION}-alpine AS uilayer - +# Build images are reviewed immutable inputs; Dependabot proposes digest updates. +FROM node:24-bookworm@sha256:6dac556d980b7f0e5498d08f08cee0ca67798b4ad6c23964a9214920e67758d0 AS uilayer WORKDIR /app - -# Git is required for some dependencies pulled from repositories -RUN apk add --no-cache git - RUN corepack enable - -COPY ./web-app/package.json ./web-app/yarn.lock ./web-app/.yarnrc.yml ./ - -RUN yarn install - -COPY ./web-app . - +COPY web-app/package.json web-app/yarn.lock web-app/.yarnrc.yml ./ +COPY web-app/.yarn ./.yarn +RUN yarn install --immutable +COPY web-app ./ RUN yarn build && ./optimize-embed.sh -USER node +# CI exports this stage to compare the source-built UI with release assets. +FROM scratch AS web-assets +COPY --from=uilayer /app/build /build -FROM golang:${GO_VERSION}-alpine AS golayer -WORKDIR /console/ - -ADD go.mod . -ADD go.sum . - -# Get dependencies - will also be cached if we won't change mod/sum +FROM golang:1.27.1-alpine@sha256:cf6fca6641884b8433441b2b0652976f975e1d0fdd26d177eaaf8596087f3125 AS golayer +WORKDIR /console +COPY go.mod go.sum ./ RUN go mod download - -ADD . . - -ENV CGO_ENABLED=0 -ENV GO111MODULE=on - +COPY . ./ COPY --from=uilayer /app/build ./web-app/build -RUN go build -trimpath --tags=kqueue,operator -ldflags "-w -s" -a -o console ./cmd/console +ARG build_version=dev +ARG build_release_version +ARG build_commit=unknown +ARG build_short_commit +ARG build_time +ARG SOURCE_DATE_EPOCH=0 +ENV CGO_ENABLED=0 GOWORK=off +RUN release_version="${build_release_version:-${build_version#v}}"; \ + release_time="${build_time:-$(date -u -d "@${SOURCE_DATE_EPOCH}" +%Y-%m-%dT%H:%M:%SZ)}"; \ + short_commit="${build_short_commit:-$(printf '%s' "$build_commit" | cut -c1-7)}"; \ + go build -trimpath -buildvcs=false --tags=kqueue,operator \ + -ldflags "-s -w -X github.com/minio/console/pkg.ReleaseTag=${build_version} -X github.com/minio/console/pkg.CommitID=${build_commit} -X github.com/minio/console/pkg.Version=${release_version} -X github.com/minio/console/pkg.ShortCommitID=${short_commit} -X github.com/minio/console/pkg.ReleaseTime=${release_time}" \ + -o console ./cmd/console FROM scratch +ARG build_version=dev +ARG build_commit=unknown +ARG build_time +LABEL org.opencontainers.image.source="https://github.com/pgsty/silo-console" \ + org.opencontainers.image.licenses="AGPL-3.0-or-later" \ + org.opencontainers.image.version="${build_version}" \ + org.opencontainers.image.revision="${build_commit}" \ + org.opencontainers.image.created="${build_time}" +COPY --from=golayer /console/console /console +COPY LICENSE NOTICE CREDITS /usr/share/licenses/silo-console/ EXPOSE 9090 - -COPY --from=golayer /console/console . - USER 1000:1000 ENTRYPOINT ["/console"] -CMD [ "server"] +CMD ["server"] diff --git a/Makefile b/Makefile index be74449bb4..0b0317e035 100644 --- a/Makefile +++ b/Makefile @@ -2,8 +2,11 @@ PWD := $(shell pwd) GOPATH := $(shell go env GOPATH) # Sets the build version based on the output of the following command, if we are building for a tag, that's the build else it uses the current git branch as the build BUILD_VERSION:=$(shell git describe --exact-match --tags $(git log -n1 --pretty='%h') 2>/dev/null || git rev-parse --abbrev-ref HEAD 2>/dev/null) -BUILD_TIME:=$(shell date 2>/dev/null) -TAG ?= "ghcr.io/pgsty/silo-console:$(BUILD_VERSION)-dev" +BUILD_TIME:=$(shell TZ=UTC git show -s --format=%cd --date=format-local:%Y-%m-%dT%H:%M:%SZ HEAD) +BUILD_COMMIT:=$(shell git rev-parse HEAD) +BUILD_EPOCH:=$(shell git show -s --format=%ct HEAD) +IMAGE_VERSION := $(subst /,-,$(BUILD_VERSION)) +TAG ?= "ghcr.io/pgsty/silo-console:$(IMAGE_VERSION)-dev" #TAG ?= "ghcr.io/pgsty/silo-console:dev" # Retain the historical variable name for test-script compatibility. Release # gates run against a pinned SILO image; override it explicitly for an advisory @@ -25,8 +28,7 @@ getdeps: @mkdir -p ${GOPATH}/bin @if ! ${GOPATH}/bin/golangci-lint --version 2>/dev/null | grep -qF " $(GOLANGCI_VERSION) "; then \ echo "Installing golangci-lint v$(GOLANGCI_VERSION)"; \ - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/v$(GOLANGCI_VERSION)/install.sh | \ - sh -s -- -b $(GOPATH)/bin v$(GOLANGCI_VERSION); \ + go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v$(GOLANGCI_VERSION); \ fi verifiers: getdeps fmt lint replacements deps-release credits @@ -90,8 +92,8 @@ swagger-typescript-api: @(cd web-app && yarn swagger-typescript-api generate -p $(path) -o $(output) -n $(name) --custom-config ../generator.config.js) assets: - @(if [ -f "${NVM_DIR}/nvm.sh" ]; then \. "${NVM_DIR}/nvm.sh" && nvm install && nvm use && npm install -g yarn ; fi &&\ - cd web-app && corepack enable && yarn install && make build-static && yarn prettier --write . --log-level warn) + @(if [ -f "${NVM_DIR}/nvm.sh" ]; then \. "${NVM_DIR}/nvm.sh" && nvm install && nvm use ; fi &&\ + cd web-app && corepack enable && yarn install --immutable && make build-static && yarn prettier --write . --log-level warn) test-integration: @(docker stop pgsqlcontainer || true) @@ -364,7 +366,7 @@ clean: @rm -vf console docker: - @docker buildx build --output=type=docker --platform linux/amd64 -t $(TAG) --build-arg build_version=$(BUILD_VERSION) --build-arg build_time='$(BUILD_TIME)' --build-arg NODE_VERSION='$(NODE_VERSION)' . + @docker buildx build --output=type=docker --platform linux/amd64 -t $(TAG) --build-arg build_version=$(BUILD_VERSION) --build-arg build_time='$(BUILD_TIME)' --build-arg build_commit='$(BUILD_COMMIT)' --build-arg build_short_commit='$(shell git show --format=%h HEAD --quiet)' --build-arg SOURCE_DATE_EPOCH='$(BUILD_EPOCH)' . release: swagger-gen @echo "Generating Release: $(RELEASE)" diff --git a/api/configure_console.go b/api/configure_console.go index 1c7fae29d2..3005212cd5 100644 --- a/api/configure_console.go +++ b/api/configure_console.go @@ -360,7 +360,7 @@ func debugLogHeaders(sb *strings.Builder, h http.Header) { // The middleware configuration happens before anything, this middleware also applies to serving the swagger.json document. // So this is a good place to plug in a panic handling middleware, logger and metrics func setupGlobalMiddleware(handler http.Handler) http.Handler { - gnext := gzhttp.GzipHandler(handler) + gnext := gzhttp.GzipHandler(downloadFormMiddleware(handler)) // if audit-log is enabled console will log all incoming request next := AuditLogMiddleware(gnext) // serve static files diff --git a/api/download_form.go b/api/download_form.go new file mode 100644 index 0000000000..8821eb2d9b --- /dev/null +++ b/api/download_form.go @@ -0,0 +1,65 @@ +// Copyright (c) 2026 PGSTY +// SPDX-License-Identifier: AGPL-3.0-or-later + +package api + +import ( + "bytes" + "encoding/json" + "io" + "mime" + "net/http" + "net/url" + "strings" +) + +// Native browser downloads cannot send JSON or custom headers. Normalize only +// this read-only operation, then retain its normal authentication and ZIP error +// handling. JSON clients and every other API operation are unchanged. +func downloadFormMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + mediaType, _, _ := mime.ParseMediaType(r.Header.Get("Content-Type")) + parts := strings.Split(strings.TrimPrefix(r.URL.Path, "/api/v1/"), "/") + if r.Method != http.MethodPost || !strings.HasPrefix(r.URL.Path, "/api/v1/") || len(parts) != 4 || parts[0] != "buckets" || parts[2] != "objects" || parts[3] != "download-multiple" || mediaType != "application/x-www-form-urlencoded" { + next.ServeHTTP(w, r) + return + } + // This endpoint renders no UI. Allow the same-origin download frame to + // read error responses, including rejected origins/selections; retain + // the framing restriction for every other API and Console page. + w.Header().Set("X-Frame-Options", "SAMEORIGIN") + // Reuse the Console origin policy, including configured external origins + // and explicitly trusted proxies for embedded/subpath installations. + if !wsCheckOrigin(r) { + http.Error(w, "download origin is not allowed", http.StatusForbidden) + return + } + r.Body = http.MaxBytesReader(w, r.Body, 2<<20) + body, err := io.ReadAll(r.Body) + if err != nil { + http.Error(w, "download selection is too large", http.StatusRequestEntityTooLarge) + return + } + values, err := url.ParseQuery(string(body)) + var objects []string + if err != nil || len(values["objects"]) != 1 || json.Unmarshal([]byte(values.Get("objects")), &objects) != nil || len(objects) == 0 || len(objects) > 1000 { + http.Error(w, "invalid download selection", http.StatusBadRequest) + return + } + for _, object := range objects { + if object == "" || len(object) > 1024 { + http.Error(w, "invalid object name", http.StatusBadRequest) + return + } + } + if values.Get("anonymous") == "1" { + r.Header.Set("X-Anonymous", "1") + } + payload := []byte(values.Get("objects")) + r.Body = io.NopCloser(bytes.NewReader(payload)) + r.ContentLength = int64(len(payload)) + r.Header.Set("Content-Type", "application/json") + r.Header.Del("Content-Length") + next.ServeHTTP(w, r) + }) +} diff --git a/api/download_form_test.go b/api/download_form_test.go new file mode 100644 index 0000000000..d3cdec91bd --- /dev/null +++ b/api/download_form_test.go @@ -0,0 +1,97 @@ +// Copyright (c) 2026 PGSTY +// SPDX-License-Identifier: AGPL-3.0-or-later +package api + +import ( + "encoding/json" + "io" + "net/http" + "net/http/httptest" + "net/url" + "reflect" + "strings" + "testing" +) + +func TestDownloadForm(t *testing.T) { + path := "/api/v1/buckets/test/objects/download-multiple" + names := []string{"a%2Fb", "a+b", "中文目录/", "a&b"} + encoded, _ := json.Marshal(names) + for _, anonymous := range []string{"0", "1"} { + t.Run("anonymous="+anonymous, func(t *testing.T) { + request := httptest.NewRequest(http.MethodPost, path, strings.NewReader(url.Values{"objects": {string(encoded)}, "anonymous": {anonymous}}.Encode())) + request.Header.Set("Content-Type", "application/x-www-form-urlencoded") + request.Header.Set("Origin", "http://example.com") + next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var got []string + if err := json.NewDecoder(r.Body).Decode(&got); err != nil || !reflect.DeepEqual(got, names) { + t.Fatalf("body = %v, err = %v", got, err) + } + if r.Header.Get("Content-Type") != "application/json" { + t.Fatal("missing JSON content type") + } + if (r.Header.Get("X-Anonymous") == "1") != (anonymous == "1") { + t.Fatal("wrong anonymous mode") + } + w.WriteHeader(http.StatusNoContent) + }) + response := httptest.NewRecorder() + downloadFormMiddleware(next).ServeHTTP(response, request) + if response.Code != http.StatusNoContent { + t.Fatalf("status=%d: %s", response.Code, response.Body.String()) + } + if response.Header().Get("X-Frame-Options") != "SAMEORIGIN" { + t.Fatal("native form responses must be readable by the same-origin frame") + } + }) + } + for _, body := range []string{"objects=null", "objects=%7B", "objects=%5B%5D", "objects=%5B1%5D", url.Values{"objects": {`[""]`}}.Encode()} { + request := httptest.NewRequest(http.MethodPost, path, strings.NewReader(body)) + request.Header.Set("Content-Type", "application/x-www-form-urlencoded") + response := httptest.NewRecorder() + downloadFormMiddleware(http.HandlerFunc(func(http.ResponseWriter, *http.Request) { t.Fatal("invalid selection reached handler") })).ServeHTTP(response, request) + if response.Code != http.StatusBadRequest { + t.Fatalf("%s: %d", body, response.Code) + } + } +} + +func TestDownloadFormBoundaries(t *testing.T) { + const path = "/api/v1/buckets/test/objects/download-multiple" + for _, tc := range []struct { + name, body, origin string + status int + }{ + {"cross origin", "objects=%5B%22a%22%5D", "https://untrusted.invalid", 403}, + {"oversized", strings.Repeat("x", (2<<20)+1), "", 413}, + } { + t.Run(tc.name, func(t *testing.T) { + request := httptest.NewRequest(http.MethodPost, path, strings.NewReader(tc.body)) + request.Header.Set("Content-Type", "application/x-www-form-urlencoded") + if tc.origin != "" { + request.Header.Set("Origin", tc.origin) + } + response := httptest.NewRecorder() + downloadFormMiddleware(http.HandlerFunc(func(http.ResponseWriter, *http.Request) { t.Fatal("rejected form reached handler") })).ServeHTTP(response, request) + if response.Code != tc.status { + t.Fatalf("status=%d", response.Code) + } + if response.Header().Get("X-Frame-Options") != "SAMEORIGIN" { + t.Fatal("native form error responses must remain readable") + } + }) + } + t.Run("JSON clients unchanged", func(t *testing.T) { + request := httptest.NewRequest(http.MethodPost, path, strings.NewReader(`["a"]`)) + request.Header.Set("Content-Type", "application/json") + downloadFormMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + b, _ := io.ReadAll(r.Body) + if string(b) != `["a"]` { + t.Fatal(string(b)) + } + if w.Header().Get("X-Frame-Options") != "" { + t.Fatal("JSON clients must retain the configured framing policy") + } + })).ServeHTTP(httptest.NewRecorder(), request) + }) +} diff --git a/docs/TLS.md b/docs/TLS.md index 7e12ace1d1..747e6fef46 100644 --- a/docs/TLS.md +++ b/docs/TLS.md @@ -1,5 +1,12 @@ ## Start Console service with TLS: +For packaged Linux services, the unit explicitly uses `/etc/silo-console/certs`, +with private CAs under `/etc/silo-console/certs/CAs`. See the +[package upgrade instructions](../systemd/README.md#upgrading-an-installation-with-existing-certificates) +before restarting an installation whose certificates are in the old default +directory. The `~/.console/certs` examples below apply to manual standalone +invocations without `--certs-dir`. + Copy your `public.crt` and `private.key` to `~/.console/certs`, then: ```sh diff --git a/docs/release-contract.md b/docs/release-contract.md new file mode 100644 index 0000000000..f36601b3b6 --- /dev/null +++ b/docs/release-contract.md @@ -0,0 +1,130 @@ +# Release and verification contract + +This contract applies to releases built from this source revision onward. Older +releases do not retroactively acquire signatures or provenance. + +## Deterministic inputs + +Release binaries, archives and DEB/RPM/APK packages use the tagged commit's UTC +committer timestamp. Build execution time is not embedded in them. The same +commit timestamp supplies `SOURCE_DATE_EPOCH` to OCI builds. Archive ownership, +binary modification times and package file times are normalized. + +Use Go **1.27.1**, Node **24.21.0**, Yarn **4.13.0**, GoReleaser **2.17.1**, +Docker Buildx **0.36.1** and the reviewed image digests in `Dockerfile`. Build +from a clean checkout with `GOWORK=off`, `CGO_ENABLED=0`, `TZ=UTC` and `LC_ALL=C`. +Use the committed `go.sum`, Yarn lockfile and Yarn patches without local module +replacements. The source image consumes the same version, full/short commit and +UTC release time as GoReleaser. Its Go build intentionally omits VCS metadata +because `.git` is outside the container context; equivalence checks compare the +reported release version and rebuilt frontend assets, not the executable hash. + +Run `hack/check-reproducible.sh` from a committed tree. It creates independent +checkouts and Go build caches, rebuilds binaries, bundles, packages and source +archives, then compares their sorted SHA-256 manifests. `hack/check-container-equivalence.sh` +runs after a GoReleaser snapshot on Linux amd64 and checks source-image metadata +and every frontend asset against the release inputs. Both checks run in CI. + +nFPM 2.47.0 embeds the source mtime of APK lifecycle scripts and iterates multiple +scripts in unspecified map order. The build normalizes those source mtimes, and +the stock Alpine package carries only its account-creation hook. Debian/RPM +retain their systemd reload/removal hooks through format-specific overrides. + +SBOM creation timestamps, SPDX namespaces, package identifiers and graph ordering +are normalized for binary, package and source SBOMs. Identifiers derive from all +emitted package fields; identical records are deduplicated and their references +updated. SBOMs are included in the reproducibility check, so the entire checksum +manifest can be reproduced. Signatures, transparency-log entries, provenance statements +and registry-generated metadata are evidence produced at signing time; they are +not byte-reproducible release payloads. The reproducibility job excludes signing +and Docker publication; registry image digest reproducibility +across BuildKit versions is not asserted by that job. + +## CI dependency review + +All Actions use full commit SHAs with version comments. Browser tools (including +TestCafe and the MinIO test client) come from `web-app/yarn.lock`, installed with +`yarn install --immutable`. CI never adds dependencies at runtime. Semgrep and its +transitive Python dependencies are hash-locked in `.github/requirements/semgrep.txt` +for Python 3.12 on Linux x86_64. Regenerate that file from `semgrep.in` with the +command recorded in its header and review the complete change. Go tools use +explicit module versions verified through the Go module checksum database. +TestCafe uses Firefox **155.0.1** from Mozilla's release archive, verified against +the SHA-512 digest in `.github/requirements/firefox.env`; the runner's system +Firefox is not selected. Review that version and digest together when updating. + +Dependabot proposes reviewed updates for Actions, Go, Yarn, Python and Docker. +There is no automatic merge policy. Cache keys use the lockfile/tool version or +an exact workflow run for artifacts shared by jobs; an artifact cache from a +different run is not accepted. Production JavaScript advisories are gated +separately from the high-severity gate covering all development/test dependencies. +The Go vulnerability gate remains independent. + +## Signatures, SBOMs and provenance + +The tag workflow uses Sigstore keyless signing with Cosign **3.1.3** and GitHub's +OIDC identity. It signs checksum manifests and OCI images, publishes SPDX SBOMs +from Syft **1.51.1** for binaries, packages, source and images, and creates GitHub +build provenance for the checksum manifest and OCI image digest. The source SBOM +contains the locked Go/JavaScript graph, including development dependencies; +artifact SBOMs describe what the corresponding binary/package/image scanner can +identify. Consult both when auditing bundled JavaScript. + +The checksum manifest binds each binary, package and source SBOM to its digest. +CI verifies manifest/image signatures, image SBOM attestations and build +provenance before declaring a draft ready to publish. Git tag signatures are +optional: the mandatory identity is the release workflow at the exact tag and +validated commit. No managed signing key is stored, so there is no managed-key +rotation procedure. Restrict write access to the repository, tag workflow and +Actions OIDC permissions; investigate/revoke affected release digests if that +identity is compromised. + +Download the binary/package, its checksum manifest and `.sigstore.json` bundle +from the same GitHub release. Example (replace `vX.Y.Z` and filenames): + +```sh +identity='https://github.com/pgsty/silo-console/.github/workflows/release.yaml@refs/tags/vX.Y.Z' +issuer='https://token.actions.githubusercontent.com' +cosign verify-blob --bundle silo-console_X.Y.Z_checksums.txt.sigstore.json \ + --certificate-identity "$identity" --certificate-oidc-issuer "$issuer" \ + silo-console_X.Y.Z_checksums.txt +gh attestation verify silo-console_X.Y.Z_checksums.txt --repo pgsty/silo-console +sha256sum --ignore-missing --check silo-console_X.Y.Z_checksums.txt +cosign verify --certificate-identity "$identity" --certificate-oidc-issuer "$issuer" \ + ghcr.io/pgsty/silo-console@sha256:IMAGE_DIGEST +gh attestation verify oci://ghcr.io/pgsty/silo-console@sha256:IMAGE_DIGEST \ + --repo pgsty/silo-console +``` + +For offline checksum verification, prepare Cosign's trusted Sigstore root/cache +on a connected machine (`cosign initialize`) and transfer it with the verification +material. Use `cosign verify-blob --offline` with the same bundle, issuer and +identity constraints, then check the artifact hashes locally. Do not substitute +an untrusted root supplied beside an untrusted artifact. GitHub's online +attestation lookup is a separate check; retain its downloaded bundle if offline +provenance verification is needed. + +## Publication and GHCR + +GHCR is intended to distribute public release images. Creating a release tag +builds the candidate version image and draft GitHub release. **It never advances +`latest`.** The tag workflow refuses to overwrite a published release. A draft +retry may replace candidate artifacts after reproducing and verifying them. + +After a maintainer publishes the verified draft, `promote-image.yaml` verifies +that it is the current stable GitHub release, checks the signatures, SBOM +attestation and provenance for its exact image digest, and tests anonymous access +with an empty Docker credential directory. Only then does it promote that digest +to `latest`. Drafts, prereleases, older release events and failed verification do +not advance `latest`. Publication events are serialized and the latest release +is checked again immediately before promotion. + +The package owner must make the GHCR package public and grant the release +workflow write access. If anonymous pulls fail, correct package visibility or +access and rerun the failed promotion job. A successful authenticated push does +not prove anonymous availability. Never claim that a draft or a green repository +build is a coordinated SILO product release. + +References: [GoReleaser reproducibility](https://goreleaser.com/blog/reproducible-builds/), +[GoReleaser signing](https://goreleaser.com/customization/sign/sign/), +[GitHub artifact attestations](https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations). diff --git a/docs/ui-downloads-and-recovery.md b/docs/ui-downloads-and-recovery.md new file mode 100644 index 0000000000..623b2bff8a --- /dev/null +++ b/docs/ui-downloads-and-recovery.md @@ -0,0 +1,46 @@ +# Browser downloads, recovery and UI text + +Multi-selection ZIPs use a file writer when the browser offers the File System +Access API. The response is streamed with backpressure, and cancelling a queued +or active transfer aborts the request and file writer. A failed or incomplete +stream never closes the writer as a completed file. Progress is determinate only +when the response supplies a reliable content length; recursive ZIPs normally +have no such total. A file-size sum is not a ZIP content length. + +Other browsers submit a same-origin native download form to the existing ZIP +operation. The normal Console authentication, anonymous access and server ZIP +error behavior remain in effect. The browser download manager owns progress, +cancellation and network errors. Console shows this handoff explicitly instead +of reporting a completed 100% archive. Dismiss the transfer entry before starting +the same selection again; doing so does not cancel an already handed-off browser +download. Use the browser download manager to cancel it. + +Selections above **5 GiB**, or with unknown total size, display a recommendation +to use `mcli` for long-running transfers. No multi-selection path buffers the +complete archive in JavaScript. Native form requests are bounded to the current +page's maximum 1,000 selections and a 2 MiB encoded request; this bounds the +selection description, not the size of the downloaded archive. Individual +bounded object downloads retain their existing XHR path. + +Invalid percent encoding produces the localized not-found screen before route +components run. Valid Unicode and encoded literal percent/slash characters are +still decoded exactly once by the existing object identity helpers. Invalid +stored sidebar values fall back to an open sidebar. Blocked storage does not +prevent reading the default language/theme or changing them for the session. +The root render boundary offers reload and home actions without clearing any +preferences, credentials or unrelated local storage. + +UI prose uses the existing English-keyed `useT`/`translate` dictionaries. Icon +controls require explicit localized accessible names. Console tooltips support +focus, Escape dismissal, hover and `aria-describedby`; labels do not depend on +tooltip visibility. The MDS sign-out control lacks a label prop, so its actual +text and accessible name are localized after rendering, with no CSS-generated +replacement text. + +`web-app/hack/ui-source-guard.mjs` runs with the frontend unit suite and inventories +literal JSX text and icon controls. Its explicit exclusions are protocol/API and +command tokens, product/legal names, the typed confirmation token, version/unit +notation and the internal component/icon catalogues. Raw object names and log +payloads remain untouched. New prose must go through translation rather than be +added to the exclusion set. English/Chinese browser rendering and navigation +checks supplement the source guard. diff --git a/hack/check-ci-contract.py b/hack/check-ci-contract.py new file mode 100644 index 0000000000..d46119b8ca --- /dev/null +++ b/hack/check-ci-contract.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +"""Fail validation when mutable Actions or unlocked test tools reappear.""" +from pathlib import Path +import re +errors = [] +for path in Path('.github/workflows').glob('*.yaml'): + source = path.read_text() + for line in source.splitlines(): + if re.search(r'\buses:', line) and not re.search(r'@[a-f0-9]{40}\s+#\s+v\d', line): + errors.append(f'{path}: Action must use a full SHA with version comment: {line.strip()}') + for pattern in (r'\byarn add\b', r'\bnpm install\b', r'\bnpx testcafe\b', r'pip3? install semgrep', r'FIREFOX_VERSION:\s*latest'): + if re.search(pattern, source): + errors.append(f'{path}: unlocked runtime dependency: {pattern}') +firefox = Path('.github/requirements/firefox.env').read_text() +if not re.search(r'^FIREFOX_VERSION=\d+\.\d+(?:\.\d+)?$', firefox, re.M) or not re.search(r'^FIREFOX_SHA512=[a-f0-9]{128}$', firefox, re.M): + errors.append('Firefox must have a reviewed release version and SHA-512 digest') +if errors: + raise SystemExit('\n'.join(errors)) +print('CI dependency contract passed') diff --git a/hack/check-container-equivalence.sh b/hack/check-container-equivalence.sh new file mode 100755 index 0000000000..eeefc3af74 --- /dev/null +++ b/hack/check-container-equivalence.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +# Run after the snapshot artifact verifier with an amd64-capable Docker builder. +set -euo pipefail +work="$(mktemp -d)" +image="silo-console-equivalence:$(git rev-parse --short HEAD)" +container="" +cleanup() { + if [ -n "$container" ]; then docker rm -f "$container" >/dev/null; fi + docker image rm "$image" >/dev/null 2>&1 || true + rm -rf "$work" +} +trap cleanup EXIT +commit="$(git rev-parse HEAD)" +tag="$(jq -r .tag dist/metadata.json)" +version="$(jq -r .version dist/metadata.json)" +short="$(git show --format=%h HEAD --quiet)" +time="$(TZ=UTC git show -s --format=%cd --date=format-local:%Y-%m-%dT%H:%M:%SZ HEAD)" +epoch="$(git show -s --format=%ct HEAD)" +docker buildx build --load --platform linux/amd64 -t "$image" \ + --build-arg "build_version=$tag" --build-arg "build_release_version=$version" \ + --build-arg "build_commit=$commit" --build-arg "build_short_commit=$short" \ + --build-arg "build_time=$time" --build-arg "SOURCE_DATE_EPOCH=$epoch" . +container="$(docker create "$image")" +docker cp "$container:/console" "$work/console" +chmod +x "$work/console" +release_binary="$(jq -r 'first(.[] | select(.type == "Binary" and .goos == "linux" and .goarch == "amd64") | .path)' dist/artifacts.json)" +[ -n "$release_binary" ] +# The CLI includes argv[0] in --version; use the same executable path in both. +diff -u <(docker run --rm --platform linux/amd64 --entrypoint /console \ + -v "$PWD/$release_binary:/console:ro" "$image" --version) \ + <(docker run --rm --platform linux/amd64 "$image" --version) +# Also compare all injected fields, including the full commit, tag and release +# timestamp which the short --version output does not expose. +go version -m "$release_binary" | awk '$1 == "build" && $2 ~ /^-ldflags=/' > "$work/release.ldflags" +go version -m "$work/console" | awk '$1 == "build" && $2 ~ /^-ldflags=/' > "$work/source.ldflags" +test -s "$work/release.ldflags" && test -s "$work/source.ldflags" +diff -u "$work/release.ldflags" "$work/source.ldflags" +docker buildx build --platform linux/amd64 --target web-assets --output "type=local,dest=$work/assets" . +diff -r web-app/build "$work/assets/build" +echo "Source image and release binary/assets agree for $commit" diff --git a/hack/check-package-lifecycle.sh b/hack/check-package-lifecycle.sh new file mode 100755 index 0000000000..750811ea67 --- /dev/null +++ b/hack/check-package-lifecycle.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +# Linux CI driver. All installation and forced-stop tests run in disposable +# containers; only package files and the test script are copied into them. +set -euo pipefail +repo="$(git rev-parse --show-toplevel)" +work="$(mktemp -d)" +container="" +cleanup() { + if [ -n "$container" ]; then docker rm -f "$container" >/dev/null; fi + rm -rf "$work" +} +trap cleanup EXIT +architecture="${PACKAGE_TEST_ARCH:-amd64}" +baseline=v2.4.0 +gh release download "$baseline" --repo pgsty/silo-console --dir "$work" \ + --pattern "*_linux_${architecture}.deb" --pattern "*_linux_${architecture}.rpm" \ + --pattern "*_linux_${architecture}.apk" --pattern '*_checksums.txt' +(cd "$work" && sha256sum --check --ignore-missing ./*_checksums.txt) +for family in deb rpm apk; do + image="console-package-test:$family" + docker build -t "$image" -f ".github/packaging/Dockerfile.$family" .github/packaging + package="$(jq -r --arg family "$family" --arg arch "$architecture" '.[] | select(.type == "Linux Package" and .goarch == $arch and (.path | endswith("." + $family))) | .path' dist/artifacts.json)" + test -n "$package" + for scenario in clean-install upgrade; do + # A fresh container for each scenario proves account/directory creation; + # an older package must not mask a missing preinstall hook. + container="$(docker run -d --privileged --cgroupns=host --tmpfs /run --tmpfs /tmp "$image")" + docker exec "$container" mkdir -p /opt/package-test + docker cp "$package" "$container:/opt/package-test/current.$family" + docker cp "$work/silo-console_2.4.0_linux_${architecture}.$family" "$container:/opt/package-test/previous.$family" + docker cp "$repo/hack/test-package-lifecycle.sh" "$container:/opt/package-test/check-package.sh" + if [ "$family" != apk ]; then + for _ in $(seq 1 30); do + if docker exec "$container" systemctl show-environment >/dev/null 2>&1; then break; fi + sleep 1 + done + fi + previous="/opt/package-test/current.$family" + if [ "$scenario" = upgrade ]; then previous="/opt/package-test/previous.$family"; fi + echo "Testing $family $scenario" + docker exec "$container" bash /opt/package-test/check-package.sh "/opt/package-test/current.$family" "$previous" + docker rm -f "$container" >/dev/null + container="" + done +done diff --git a/hack/check-reproducible.sh b/hack/check-reproducible.sh new file mode 100755 index 0000000000..3329e3c792 --- /dev/null +++ b/hack/check-reproducible.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# Build the same commit in two independent checkouts, normalizing timestamps +# from that commit. Keep signed/OIDC statements out of the byte-for-byte check. +set -euo pipefail +root="$(git rev-parse --show-toplevel)" +commit="$(git rev-parse HEAD)" +work="$(mktemp -d)" +trap 'rm -rf "$work"' EXIT +for attempt in one two; do + git clone --quiet --no-local "$root" "$work/$attempt" + git -C "$work/$attempt" checkout --quiet --detach "$commit" + ( + cd "$work/$attempt" + export GOWORK=off CGO_ENABLED=0 TZ=UTC LC_ALL=C + SOURCE_DATE_EPOCH="$(git show -s --format=%ct HEAD)" + export SOURCE_DATE_EPOCH + # Separate build caches prevent a cache hit from masquerading as a rebuild. + export GOCACHE="$work/cache-$attempt" + goreleaser release --snapshot --clean --skip=publish,announce,sign,docker > "$work/$attempt.log" 2>&1 || { tail -60 "$work/$attempt.log"; exit 1; } + LC_ALL=C sort dist/*_checksums.txt > "$work/$attempt.sha256" + ) +done +diff -u "$work/one.sha256" "$work/two.sha256" +echo "Binaries, bundles, packages, source and SBOMs reproduced for $commit" diff --git a/hack/generate-sbom.sh b/hack/generate-sbom.sh new file mode 100755 index 0000000000..3f90026d67 --- /dev/null +++ b/hack/generate-sbom.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +# GoReleaser calls this for each binary/package before constructing checksums. +set -euo pipefail +artifact="$1" output="$2" +syft scan "file:$artifact" -o "spdx-json=$output" --quiet +python3 - "$artifact" "$output" "$(git show -s --format=%ct HEAD)" <<'PY' +import datetime, hashlib, json, pathlib, sys +artifact, output, epoch = sys.argv[1:] +path = pathlib.Path(output) +data = json.loads(path.read_text()) +digest = hashlib.sha256(pathlib.Path(artifact).read_bytes()).hexdigest() +data['creationInfo']['created'] = datetime.datetime.fromtimestamp(int(epoch), datetime.timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ') +data['documentNamespace'] = 'https://github.com/pgsty/silo-console/sbom/' + digest +# Syft can assign different internal IDs to the same emitted npm package +# between scans. Derive IDs from all published package fields, update their +# references, and order the graph without dropping any distinct package data. +canonical = lambda value: json.dumps(value, sort_keys=True, separators=(',', ':')) +identifiers, packages = {}, {} +for package in data.get('packages', []): + record = {key: value for key, value in package.items() if key != 'SPDXID'} + identifier = 'SPDXRef-Package-' + hashlib.sha256(canonical(record).encode()).hexdigest() + identifiers[package['SPDXID']] = identifier + packages[identifier] = {**record, 'SPDXID': identifier} +data['packages'] = [packages[key] for key in sorted(packages)] +relationships = {} +for relationship in data.get('relationships', []): + for key in ('spdxElementId', 'relatedSpdxElement'): + relationship[key] = identifiers.get(relationship[key], relationship[key]) + relationships[canonical(relationship)] = relationship +data['relationships'] = [relationships[key] for key in sorted(relationships)] +if 'documentDescribes' in data: + data['documentDescribes'] = sorted({identifiers.get(value, value) for value in data['documentDescribes']}) +path.write_text(json.dumps(data, sort_keys=True, separators=(',', ':')) + '\n') +PY diff --git a/hack/install-ci-firefox.sh b/hack/install-ci-firefox.sh new file mode 100644 index 0000000000..1f42ea2a04 --- /dev/null +++ b/hack/install-ci-firefox.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +# Install the reviewed browser in a runner-owned directory, never from "latest" +# or the runner image's unversioned system browser. +set -euo pipefail +root="$(cd "$(dirname "$0")/.." && pwd)" +# shellcheck source-path=SCRIPTDIR +# shellcheck source=../.github/requirements/firefox.env +source "$root/.github/requirements/firefox.env" +: "${RUNNER_TEMP:?GitHub runner temporary directory is required}" +: "${GITHUB_PATH:?GitHub runner path file is required}" +install_dir="$(mktemp -d "$RUNNER_TEMP/firefox.XXXXXX")" +archive="$install_dir/firefox.tar.xz" +curl --fail --location --retry 3 --connect-timeout 20 --max-time 180 \ + "https://archive.mozilla.org/pub/firefox/releases/$FIREFOX_VERSION/linux-x86_64/en-US/firefox-$FIREFOX_VERSION.tar.xz" \ + --output "$archive" +printf '%s %s\n' "$FIREFOX_SHA512" "$archive" | sha512sum --check --strict +tar -xf "$archive" -C "$install_dir" +rm "$archive" +"$install_dir/firefox/firefox" --version +echo "$install_dir/firefox" >> "$GITHUB_PATH" diff --git a/hack/normalize-package-inputs.py b/hack/normalize-package-inputs.py new file mode 100644 index 0000000000..ff78f106da --- /dev/null +++ b/hack/normalize-package-inputs.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python3 +"""nFPM's APK script headers use source mtime rather than the package mtime.""" +import os +from pathlib import Path +import subprocess + +epoch = int(subprocess.check_output(["git", "show", "-s", "--format=%ct", "HEAD"], text=True).strip()) +for path in Path("systemd").glob("*.sh"): + os.utime(path, (epoch, epoch)) diff --git a/hack/test-package-lifecycle.sh b/hack/test-package-lifecycle.sh new file mode 100755 index 0000000000..4c673d5296 --- /dev/null +++ b/hack/test-package-lifecycle.sh @@ -0,0 +1,107 @@ +#!/usr/bin/env bash +# Run only in a disposable Linux package-test container/VM, never on the host. +# Usage: hack/test-package-lifecycle.sh /path/to/package.deb [previous-package] +set -euo pipefail +package="$1" +install_package() { + case "$1" in + *.deb) dpkg -i "$1" ;; + *.rpm) rpm -Uvh --replacepkgs "$1" ;; + *.apk) apk add --allow-untrusted --force-overwrite "$1" ;; + *) echo "Unsupported package: $1" >&2; exit 1 ;; + esac +} +install_package "${2:-$package}" +# Simulate operator configuration/state and ensure the upgrade retains them. +printf '\n# lifecycle-test-kept\n' >> /etc/default/console +install -d -m 0750 -o console-user -g console-user /var/lib/silo-console +touch /var/lib/silo-console/keep-state +# Seed real certificates before the upgrade, including the old default path. +cert_dir=/etc/silo-console/certs +if [ "${2:-$package}" != "$package" ]; then + cert_dir="$(getent passwd console-user | cut -d: -f6)/.console/certs" +fi +install -d -m 0750 -o root -g console-user "$cert_dir" "$cert_dir/CAs" +openssl req -x509 -nodes -newkey rsa:2048 -days 1 -subj /CN=localhost \ + -addext subjectAltName=DNS:localhost,IP:127.0.0.1 \ + -keyout "$cert_dir/private.key" -out "$cert_dir/public.crt" >/dev/null 2>&1 +cp "$cert_dir/public.crt" "$cert_dir/CAs/test.crt" +chown root:console-user "$cert_dir/private.key" "$cert_dir/public.crt" "$cert_dir/CAs/test.crt" +chmod 0640 "$cert_dir/private.key" "$cert_dir/public.crt" "$cert_dir/CAs/test.crt" +certificate_hashes="$(sha256sum "$cert_dir/private.key" "$cert_dir/public.crt" "$cert_dir/CAs/test.crt")" +if [ "$cert_dir" != /etc/silo-console/certs ]; then + # Operators also symlink the complete legacy certificate directory. The + # warning and explicit path override must work without replacing that link. + mv "$cert_dir" "$cert_dir.saved" + ln -s "$cert_dir.saved" "$cert_dir" +fi +upgrade_log=$(mktemp) +if ! install_package "$package" >"$upgrade_log" 2>&1; then cat "$upgrade_log"; exit 1; fi +cat "$upgrade_log" +if [ "$cert_dir" != /etc/silo-console/certs ] && [ -d /run/systemd/system ]; then + test -L "$cert_dir" + grep -F "existing certificates remain in $cert_dir" "$upgrade_log" + grep -F 'Before restarting minio-console.service' "$upgrade_log" + # Apply the documented operator choice to retain the old location. The + # package does not restart the service or move private keys automatically. + printf '\nCONSOLE_OPTS="--port 9090 --tls-port 9443 --certs-dir %s"\n' "$cert_dir" >> /etc/default/console +fi +# Stock Alpine has no systemd unit to activate and APK does not run a +# pre-install hook during upgrades. Its chosen supervisor and HOME are unchanged. +rm "$upgrade_log" +test "$certificate_hashes" = "$(sha256sum "$cert_dir/private.key" "$cert_dir/public.crt" "$cert_dir/CAs/test.crt")" +grep -q '^# lifecycle-test-kept$' /etc/default/console +test -f /var/lib/silo-console/keep-state +test "$(stat -c %U /var/lib/silo-console)" = console-user +test "$(stat -c %G /etc/silo-console/certs/CAs)" = console-user +/usr/local/bin/silo-console --version +if [ -d /run/systemd/system ]; then + systemctl daemon-reload + systemctl start minio-console.service + for _ in $(seq 1 30); do + if curl -fsS http://127.0.0.1:9090/ >/dev/null; then break; fi + sleep 1 + done + curl -fsS http://127.0.0.1:9090/ >/dev/null + before="$(systemctl show minio-console.service -p MainPID --value)" + systemctl restart minio-console.service + after="$(systemctl show minio-console.service -p MainPID --value)" + test "$before" != "$after" + test "$(systemctl show minio-console.service -p TimeoutStopUSec --value)" = 1min\ 30s + # Exercise systemd escalation with a controlled process that ignores TERM; + # systemd sends SIGCONT during stop, so SIGSTOP alone cannot model a hang. + systemctl stop minio-console.service + mkdir -p /etc/systemd/system/minio-console.service.d + cat > /etc/systemd/system/minio-console.service.d/stop-test.conf <<'UNIT' +[Service] +TimeoutStopSec=1 +ExecStart= +ExecStart=/bin/sh -c 'trap "" TERM; exec sleep infinity' +UNIT + systemctl daemon-reload + systemctl start minio-console.service + sleep 1 + timeout 10 systemctl stop minio-console.service || true + test "$(systemctl show minio-console.service -p MainPID --value)" = 0 + test "$(systemctl show minio-console.service -p Result --value)" = timeout + rm /etc/systemd/system/minio-console.service.d/stop-test.conf + systemctl daemon-reload + systemctl reset-failed minio-console.service + # The listener must use the same private certificate seeded before upgrade. + systemctl start minio-console.service + for _ in $(seq 1 30); do + if curl --cacert "$cert_dir/CAs/test.crt" -fsS https://localhost:9443/ >/dev/null; then break; fi + sleep 1 + done + curl --cacert "$cert_dir/CAs/test.crt" -fsS https://localhost:9443/ >/dev/null +fi +case "$package" in + *.deb) dpkg --remove silo-console ;; + *.rpm) rpm -e silo-console ;; + *.apk) apk del silo-console ;; +esac +test -f /var/lib/silo-console/keep-state +if [ -d /run/systemd/system ]; then + if systemctl is-active --quiet minio-console.service; then exit 1; fi +fi +echo "Install, upgrade, runtime ownership and removal verified: $package" diff --git a/hack/verify-release-artifacts.sh b/hack/verify-release-artifacts.sh index 7d35a7c0ea..4cab8a6ccb 100755 --- a/hack/verify-release-artifacts.sh +++ b/hack/verify-release-artifacts.sh @@ -56,7 +56,7 @@ case "$mode" in else have goreleaser log "building a snapshot" - goreleaser release --snapshot --clean >"$work/goreleaser.log" 2>&1 || { tail -50 "$work/goreleaser.log" >&2; fail "goreleaser snapshot failed"; } + goreleaser release --snapshot --clean --skip=sign >"$work/goreleaser.log" 2>&1 || { tail -50 "$work/goreleaser.log" >&2; fail "goreleaser snapshot failed"; } fi assets_dir="dist"; metadata_dir="dist"; tag="" ;; diff --git a/systemd/README.md b/systemd/README.md index 7771ed9fba..62631ba3b0 100644 --- a/systemd/README.md +++ b/systemd/README.md @@ -1,66 +1,89 @@ -# Systemd service for Console - -Systemd script for Console. - -## Installation - -- Systemd script is configured to run `/usr/local/bin/silo-console`. -- Systemd script is configured to run the binary as `console-user`. DEB/RPM/APK - packages create this system user automatically (`preinstall.sh`); for manual - installations, create it yourself before using the service script. -- Release binaries and packages are available from the - [release page](https://github.com/pgsty/silo-console/releases). Source builds - remain available through the [README](https://github.com/pgsty/silo-console#quick-start). -- DEB and RPM packages currently retain the compatibility service name - `/etc/systemd/system/minio-console.service`; renaming it requires a package - migration. Manual installations below use `console.service`. -- Packages also install a configuration template at `/etc/default/console` - (from `console.env`, marked as config/noreplace so upgrades keep your edits). - -When building from source, install the local development binary under the -release name expected by the service: +# Packaged Linux service + +DEB and RPM retain `/etc/systemd/system/minio-console.service` and +`/etc/default/console`. Existing service names and configuration files continue +to work. APK installs the same files for compatibility, but stock Alpine uses +OpenRC: run the binary under your chosen supervisor rather than assuming systemd +is available. Packages do not automatically enable or start the service. + +The service runs `/usr/local/bin/silo-console` as `console-user:console-user`, +with a working directory and `HOME` of `/var/lib/silo-console`. New accounts use +that home; upgrading an existing account does not rewrite its passwd entry. +The explicit service `HOME` handles accounts created by older packages with +`/usr/local` as their home. State is owned by the service user with mode `0750`; +`/run/silo-console` is managed by systemd and removed when the service stops. + +Certificate configuration is rooted at `/etc/silo-console/certs`, explicitly +passed with `--certs-dir`. The package creates this directory and `CAs/` as +`root:console-user`, mode `0750`. Install upstream private-CA certificates in +`CAs/`. For HTTPS on Console itself, install `public.crt` and `private.key` in +`certs/`. Files should be `root:console-user`, mode `0640`. The service reads +these files; operators manage them. Upgrades do not recursively chown or remove +existing files. Example: ```sh -sudo install -m 0755 ./console /usr/local/bin/silo-console +sudo install -o root -g console-user -m 0640 company-ca.crt \ + /etc/silo-console/certs/CAs/company-ca.crt +sudoedit /etc/default/console +sudo systemctl enable --now minio-console.service ``` -## Create the Environment configuration file - -This file serves as input to Console systemd service. +### Upgrading an installation with existing certificates + +Packages before this change used the service account's home directory, normally +`/usr/local/.console/certs`. The new unit uses `/etc/silo-console/certs`. +When the old directory contains certificates, installation prints a warning +with both paths. It preserves the old files, private keys, symlinks and passwd +entry, and does not restart the service. Complete one of these steps **before +restarting**: + +- Keep the old location by adding `--certs-dir /usr/local/.console/certs` to + `CONSOLE_OPTS` in `/etc/default/console`, retaining your other options. Use the + actual old path printed by the installer. A path under `/home`, `/root` or + `/run/user` is hidden by `ProtectHome`; migrate it to `/etc` instead. +- Install your serving certificate, private key and private CAs into the new + directory using the ownership and modes above. Preserve any domain-specific + certificate subdirectories, and check symlink targets remain readable by + `console-user`. Remove the old files only after verifying TLS and login. + +Directory ownership/modes declared by the package are reapplied on upgrade; +operator-managed certificate files are not recursively modified. + +Set `CONSOLE_MINIO_SERVER` to the maintained SILO endpoint. Stable +`CONSOLE_PBKDF_PASSPHRASE` and `CONSOLE_PBKDF_SALT` preserve sessions across +restarts; unset values invalidate sessions on restart. Keep `/etc/default/console` +root-owned with mode `0600`. `CONSOLE_OPTS` can override the certificate path or +ports, for example `--port 9090 --tls-port 9443 --certs-dir /etc/my-console/certs`. +Do not put certificates under a home directory hidden by `ProtectHome`. + +Shutdown allows **90 seconds** for SIGTERM cleanup, then systemd sends SIGKILL to +the remaining control group. A stopped/unresponsive process therefore cannot +block upgrades or removal indefinitely. The unit uses a private temporary +directory and devices, read-only system paths, inaccessible home directories, +no new privileges, an empty capability set and only Unix/IPv4/IPv6 sockets. +State and runtime directories remain writable. Use an unprivileged listening +port (9090 by default) with a reverse proxy; binding a privileged port requires +an intentional unit override. Custom writable paths need `ReadWritePaths` in a +systemd drop-in. Inspect the effective unit with `systemctl cat` after upgrades. + +Package install/upgrade reloads systemd without unexpectedly restarting a running +Console. Restart it deliberately to activate the new executable and unit: ```sh -$ cat <> /etc/default/console -# Special opts -CONSOLE_OPTS="--port 8443" - -# salt to encrypt JWT payload -CONSOLE_PBKDF_PASSPHRASE=CHANGEME - -# required to encrypt JWT payload -CONSOLE_PBKDF_SALT=CHANGEME - -# SILO or MinIO-compatible endpoint (compatibility variable retained) -CONSOLE_MINIO_SERVER=http://minio.endpoint:9000 - -EOT +sudo systemctl daemon-reload +sudo systemctl restart minio-console.service +sudo systemctl status minio-console.service ``` -## Systemctl - -Download `console.service` in `/etc/systemd/system/` - -``` -( cd /etc/systemd/system/; curl -O https://raw.githubusercontent.com/pgsty/silo-console/main/systemd/console.service ) -``` - -Enable startup on boot - -``` -systemctl enable console.service -``` - -## Note - -- Replace ``User=console-user`` and ``Group=console-user`` in console.service file with your local setup. -- Ensure that ``CONSOLE_PBKDF_PASSPHRASE`` and ``CONSOLE_PBKDF_SALT`` are set to appropriate values. -- Ensure that ``CONSOLE_MINIO_SERVER`` is set to appropriate server endpoint. +DEB/RPM removal stops/disables the compatibility unit and reloads systemd. +The stock Alpine APK creates its service account at installation and does not +run systemd lifecycle hooks. User state, +configuration and certificates are retained for explicit operator cleanup. +For source/manual installs, run `systemd/preinstall.sh` as root to create the +account/directories, install the binary as `/usr/local/bin/silo-console`, install +`console.env` as `/etc/default/console` with mode `0600`, and install +`console.service` under the compatibility unit name. + +`hack/test-package-lifecycle.sh` is for disposable Linux containers/VMs. It checks +install, upgrade/config preservation, restart, forced termination of a process that ignores TERM, TLS startup with a private CA, ownership and removal. Never run it on a +host whose existing Console data or configuration should be preserved. diff --git a/systemd/console.service b/systemd/console.service index 54fc6a7e29..8f14ff7b5e 100644 --- a/systemd/console.service +++ b/systemd/console.service @@ -4,28 +4,34 @@ Documentation=https://github.com/pgsty/silo-console Wants=network-online.target After=network-online.target AssertFileIsExecutable=/usr/local/bin/silo-console +StartLimitBurst=2 +StartLimitIntervalSec=5 [Service] -WorkingDirectory=/usr/local/ - User=console-user Group=console-user - +WorkingDirectory=/var/lib/silo-console +Environment=HOME=/var/lib/silo-console EnvironmentFile=/etc/default/console - -ExecStart=/usr/local/bin/silo-console server $CONSOLE_OPTS - -# Let systemd restart this service always +StateDirectory=silo-console +StateDirectoryMode=0750 +RuntimeDirectory=silo-console +RuntimeDirectoryMode=0750 +ExecStart=/usr/local/bin/silo-console server --certs-dir /etc/silo-console/certs $CONSOLE_OPTS Restart=always -StartLimitBurst=2 -StartLimitInterval=5 - -# Specifies the maximum file descriptor number that can be opened by this process +RestartSec=2 LimitNOFILE=65536 - -# Disable timeout logic and wait until process is stopped -TimeoutStopSec=infinity -SendSIGKILL=no +TimeoutStopSec=90 +KillMode=control-group +SendSIGKILL=yes +UMask=0027 +NoNewPrivileges=yes +PrivateTmp=yes +PrivateDevices=yes +ProtectSystem=strict +ProtectHome=yes +RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 +CapabilityBoundingSet= [Install] WantedBy=multi-user.target diff --git a/systemd/preinstall.sh b/systemd/preinstall.sh index 7c623cbc6a..46109027ab 100755 --- a/systemd/preinstall.sh +++ b/systemd/preinstall.sh @@ -4,13 +4,28 @@ set -e if ! id console-user >/dev/null 2>&1; then if command -v useradd >/dev/null 2>&1; then - useradd --system --user-group --home-dir /usr/local \ + useradd --system --user-group --home-dir /var/lib/silo-console \ --shell /sbin/nologin console-user elif command -v adduser >/dev/null 2>&1; then addgroup -S console-user 2>/dev/null || true - adduser -S -D -H -h /usr/local -s /sbin/nologin \ + adduser -S -D -H -h /var/lib/silo-console -s /sbin/nologin \ -G console-user console-user + else + echo "Cannot create console-user: neither useradd nor adduser is available" >&2 + exit 1 fi fi +# Do not recursively change ownership of existing state or operator certificates. +install -d -m 0750 -o console-user -g console-user /var/lib/silo-console +install -d -m 0750 -o root -g console-user /etc/silo-console /etc/silo-console/certs /etc/silo-console/certs/CAs + +# Older packages used the account's home (normally /usr/local) for certs. +# Keep private files in place and warn before the operator restarts the service. +legacy_home=$(getent passwd console-user | cut -d: -f6) +legacy_certs="$legacy_home/.console/certs" +if [ -n "$legacy_home" ] && [ -d "$legacy_certs" ] && [ -n "$(find "$legacy_certs/." -mindepth 1 ! -type d -print -quit)" ]; then + echo "WARNING: SILO Console service now uses /etc/silo-console/certs; existing certificates remain in $legacy_certs. Before restarting minio-console.service, migrate the certificates and CAs or set --certs-dir $legacy_certs in CONSOLE_OPTS. See /usr/share/doc/silo-console/service.md. No certificates were moved." >&2 +fi + exit 0 diff --git a/systemd/preremove.sh b/systemd/preremove.sh new file mode 100755 index 0000000000..a3adbba47a --- /dev/null +++ b/systemd/preremove.sh @@ -0,0 +1,12 @@ +#!/bin/sh +set -e +# Debian uses "remove" and RPM uses 0 for final removal. Upgrades keep the +# existing service running until the operator deliberately restarts it. +case "${1:-remove}" in + remove|deinstall|0) + if [ -d /run/systemd/system ] && command -v systemctl >/dev/null 2>&1; then + systemctl stop minio-console.service + systemctl disable minio-console.service + fi + ;; +esac diff --git a/systemd/reload.sh b/systemd/reload.sh new file mode 100755 index 0000000000..da4addb94a --- /dev/null +++ b/systemd/reload.sh @@ -0,0 +1,6 @@ +#!/bin/sh +set -e +# Installation/removal inside a container/chroot must not contact the host. +if [ -d /run/systemd/system ] && command -v systemctl >/dev/null 2>&1; then + systemctl daemon-reload +fi diff --git a/web-app/build/assets/AccessDetailsPanel-CANM2Ha0.js.gz b/web-app/build/assets/AccessDetailsPanel-CANM2Ha0.js.gz deleted file mode 100644 index 5d952a3871..0000000000 Binary files a/web-app/build/assets/AccessDetailsPanel-CANM2Ha0.js.gz and /dev/null differ diff --git a/web-app/build/assets/AccessDetailsPanel-CrN_5Cbf.js.gz b/web-app/build/assets/AccessDetailsPanel-CrN_5Cbf.js.gz new file mode 100644 index 0000000000..2c2951a29c Binary files /dev/null and b/web-app/build/assets/AccessDetailsPanel-CrN_5Cbf.js.gz differ diff --git a/web-app/build/assets/AccessRulePanel-BXybIiw-.js.gz b/web-app/build/assets/AccessRulePanel-BXybIiw-.js.gz new file mode 100644 index 0000000000..7bb4769ad7 Binary files /dev/null and b/web-app/build/assets/AccessRulePanel-BXybIiw-.js.gz differ diff --git a/web-app/build/assets/AccessRulePanel-CeYgxkQG.js.gz b/web-app/build/assets/AccessRulePanel-CeYgxkQG.js.gz deleted file mode 100644 index aa05786ed9..0000000000 Binary files a/web-app/build/assets/AccessRulePanel-CeYgxkQG.js.gz and /dev/null differ diff --git a/web-app/build/assets/Account-BUD8Blqm.js.gz b/web-app/build/assets/Account-BUD8Blqm.js.gz new file mode 100644 index 0000000000..5ff36bb68f Binary files /dev/null and b/web-app/build/assets/Account-BUD8Blqm.js.gz differ diff --git a/web-app/build/assets/Account-CCrDKH5b.js.gz b/web-app/build/assets/Account-CCrDKH5b.js.gz deleted file mode 100644 index 6279d7b270..0000000000 Binary files a/web-app/build/assets/Account-CCrDKH5b.js.gz and /dev/null differ diff --git a/web-app/build/assets/AccountUtils-BO0W1dMV.js.gz b/web-app/build/assets/AccountUtils-BO0W1dMV.js.gz new file mode 100644 index 0000000000..0e23b66f0d Binary files /dev/null and b/web-app/build/assets/AccountUtils-BO0W1dMV.js.gz differ diff --git a/web-app/build/assets/AccountUtils-W650PZPJ.js.gz b/web-app/build/assets/AccountUtils-W650PZPJ.js.gz deleted file mode 100644 index 92b658d74c..0000000000 Binary files a/web-app/build/assets/AccountUtils-W650PZPJ.js.gz and /dev/null differ diff --git a/web-app/build/assets/AddAccessRule-DJ-FoTrr.js.gz b/web-app/build/assets/AddAccessRule-DJ-FoTrr.js.gz new file mode 100644 index 0000000000..23cfc6e38b Binary files /dev/null and b/web-app/build/assets/AddAccessRule-DJ-FoTrr.js.gz differ diff --git a/web-app/build/assets/AddAccessRule-z-3HhNQH.js.gz b/web-app/build/assets/AddAccessRule-z-3HhNQH.js.gz deleted file mode 100644 index ef1374acd6..0000000000 Binary files a/web-app/build/assets/AddAccessRule-z-3HhNQH.js.gz and /dev/null differ diff --git a/web-app/build/assets/AddBucket-C4FnnkcV.js.gz b/web-app/build/assets/AddBucket-C4FnnkcV.js.gz deleted file mode 100644 index f0033a9b97..0000000000 Binary files a/web-app/build/assets/AddBucket-C4FnnkcV.js.gz and /dev/null differ diff --git a/web-app/build/assets/AddBucket-DrDNCpo-.js.gz b/web-app/build/assets/AddBucket-DrDNCpo-.js.gz new file mode 100644 index 0000000000..7e6a407eb1 Binary files /dev/null and b/web-app/build/assets/AddBucket-DrDNCpo-.js.gz differ diff --git a/web-app/build/assets/AddBucketReplication-B1qzamZR.js.gz b/web-app/build/assets/AddBucketReplication-B1qzamZR.js.gz new file mode 100644 index 0000000000..46dc890c5a Binary files /dev/null and b/web-app/build/assets/AddBucketReplication-B1qzamZR.js.gz differ diff --git a/web-app/build/assets/AddBucketReplication-D5h9r8sW.js.gz b/web-app/build/assets/AddBucketReplication-D5h9r8sW.js.gz deleted file mode 100644 index 7668dbfe78..0000000000 Binary files a/web-app/build/assets/AddBucketReplication-D5h9r8sW.js.gz and /dev/null differ diff --git a/web-app/build/assets/AddBucketTagModal-BdH_OmiE.js.gz b/web-app/build/assets/AddBucketTagModal-BdH_OmiE.js.gz new file mode 100644 index 0000000000..4146b61acf Binary files /dev/null and b/web-app/build/assets/AddBucketTagModal-BdH_OmiE.js.gz differ diff --git a/web-app/build/assets/AddBucketTagModal-DWkGMkrZ.js.gz b/web-app/build/assets/AddBucketTagModal-DWkGMkrZ.js.gz deleted file mode 100644 index d1693f55fd..0000000000 Binary files a/web-app/build/assets/AddBucketTagModal-DWkGMkrZ.js.gz and /dev/null differ diff --git a/web-app/build/assets/AddEvent-1uY7LQYv.js.gz b/web-app/build/assets/AddEvent-1uY7LQYv.js.gz new file mode 100644 index 0000000000..084ce42985 Binary files /dev/null and b/web-app/build/assets/AddEvent-1uY7LQYv.js.gz differ diff --git a/web-app/build/assets/AddEvent-l2vsP6s1.js.gz b/web-app/build/assets/AddEvent-l2vsP6s1.js.gz deleted file mode 100644 index 0066e58949..0000000000 Binary files a/web-app/build/assets/AddEvent-l2vsP6s1.js.gz and /dev/null differ diff --git a/web-app/build/assets/AddEventDestination-BBFRUGHZ.js.gz b/web-app/build/assets/AddEventDestination-BBFRUGHZ.js.gz deleted file mode 100644 index 3c229681a3..0000000000 Binary files a/web-app/build/assets/AddEventDestination-BBFRUGHZ.js.gz and /dev/null differ diff --git a/web-app/build/assets/AddEventDestination-wjeXAyfE.js.gz b/web-app/build/assets/AddEventDestination-wjeXAyfE.js.gz new file mode 100644 index 0000000000..380a8b5956 Binary files /dev/null and b/web-app/build/assets/AddEventDestination-wjeXAyfE.js.gz differ diff --git a/web-app/build/assets/AddGroupScreen-C75QT299.js.gz b/web-app/build/assets/AddGroupScreen-C75QT299.js.gz new file mode 100644 index 0000000000..da7c4b7fc2 Binary files /dev/null and b/web-app/build/assets/AddGroupScreen-C75QT299.js.gz differ diff --git a/web-app/build/assets/AddGroupScreen-DzXErdYX.js.gz b/web-app/build/assets/AddGroupScreen-DzXErdYX.js.gz deleted file mode 100644 index 5b2919d6f4..0000000000 Binary files a/web-app/build/assets/AddGroupScreen-DzXErdYX.js.gz and /dev/null differ diff --git a/web-app/build/assets/AddIDPConfigurationHelpbox-Bt3Enl03.js.gz b/web-app/build/assets/AddIDPConfigurationHelpbox-Bt3Enl03.js.gz deleted file mode 100644 index 5032e1c816..0000000000 Binary files a/web-app/build/assets/AddIDPConfigurationHelpbox-Bt3Enl03.js.gz and /dev/null differ diff --git a/web-app/build/assets/AddIDPConfigurationHelpbox-ztvRiqto.js.gz b/web-app/build/assets/AddIDPConfigurationHelpbox-ztvRiqto.js.gz new file mode 100644 index 0000000000..35936c9242 Binary files /dev/null and b/web-app/build/assets/AddIDPConfigurationHelpbox-ztvRiqto.js.gz differ diff --git a/web-app/build/assets/AddIDPOpenIDConfiguration-Cqf-TpKW.js.gz b/web-app/build/assets/AddIDPOpenIDConfiguration-Cqf-TpKW.js.gz new file mode 100644 index 0000000000..71c005ead7 Binary files /dev/null and b/web-app/build/assets/AddIDPOpenIDConfiguration-Cqf-TpKW.js.gz differ diff --git a/web-app/build/assets/AddIDPOpenIDConfiguration-W0Lfm7ZU.js.gz b/web-app/build/assets/AddIDPOpenIDConfiguration-W0Lfm7ZU.js.gz deleted file mode 100644 index 415429e14e..0000000000 Binary files a/web-app/build/assets/AddIDPOpenIDConfiguration-W0Lfm7ZU.js.gz and /dev/null differ diff --git a/web-app/build/assets/AddKey-BL-2rDl3.js.gz b/web-app/build/assets/AddKey-BL-2rDl3.js.gz new file mode 100644 index 0000000000..008e14ecb1 Binary files /dev/null and b/web-app/build/assets/AddKey-BL-2rDl3.js.gz differ diff --git a/web-app/build/assets/AddKey-X8HMShKV.js.gz b/web-app/build/assets/AddKey-X8HMShKV.js.gz deleted file mode 100644 index 8c7dbe1465..0000000000 Binary files a/web-app/build/assets/AddKey-X8HMShKV.js.gz and /dev/null differ diff --git a/web-app/build/assets/AddPolicyScreen-B0aCIKrp.js.gz b/web-app/build/assets/AddPolicyScreen-B0aCIKrp.js.gz deleted file mode 100644 index f2c96fae90..0000000000 Binary files a/web-app/build/assets/AddPolicyScreen-B0aCIKrp.js.gz and /dev/null differ diff --git a/web-app/build/assets/AddPolicyScreen-C2YBaDTd.js.gz b/web-app/build/assets/AddPolicyScreen-C2YBaDTd.js.gz new file mode 100644 index 0000000000..05ad921853 Binary files /dev/null and b/web-app/build/assets/AddPolicyScreen-C2YBaDTd.js.gz differ diff --git a/web-app/build/assets/AddReplicationModal-Bdl4Ea9D.js.gz b/web-app/build/assets/AddReplicationModal-Bdl4Ea9D.js.gz deleted file mode 100644 index 68d7dcae86..0000000000 Binary files a/web-app/build/assets/AddReplicationModal-Bdl4Ea9D.js.gz and /dev/null differ diff --git a/web-app/build/assets/AddReplicationModal-CyxDWq5n.js.gz b/web-app/build/assets/AddReplicationModal-CyxDWq5n.js.gz new file mode 100644 index 0000000000..51e7c622a3 Binary files /dev/null and b/web-app/build/assets/AddReplicationModal-CyxDWq5n.js.gz differ diff --git a/web-app/build/assets/AddReplicationSites-D5FEMbjB.js.gz b/web-app/build/assets/AddReplicationSites-D5FEMbjB.js.gz deleted file mode 100644 index c2efe4b5ec..0000000000 Binary files a/web-app/build/assets/AddReplicationSites-D5FEMbjB.js.gz and /dev/null differ diff --git a/web-app/build/assets/AddReplicationSites-r08fVK5M.js.gz b/web-app/build/assets/AddReplicationSites-r08fVK5M.js.gz new file mode 100644 index 0000000000..7ff63cb99f Binary files /dev/null and b/web-app/build/assets/AddReplicationSites-r08fVK5M.js.gz differ diff --git a/web-app/build/assets/AddServiceAccountScreen-CUalQ5TI.js.gz b/web-app/build/assets/AddServiceAccountScreen-CUalQ5TI.js.gz new file mode 100644 index 0000000000..7f2661caa9 Binary files /dev/null and b/web-app/build/assets/AddServiceAccountScreen-CUalQ5TI.js.gz differ diff --git a/web-app/build/assets/AddServiceAccountScreen-K0QOWb-H.js.gz b/web-app/build/assets/AddServiceAccountScreen-K0QOWb-H.js.gz deleted file mode 100644 index df13f1f6ee..0000000000 Binary files a/web-app/build/assets/AddServiceAccountScreen-K0QOWb-H.js.gz and /dev/null differ diff --git a/web-app/build/assets/AddTierConfiguration-BJ7D3jgf.js.gz b/web-app/build/assets/AddTierConfiguration-BJ7D3jgf.js.gz deleted file mode 100644 index 60a8962707..0000000000 Binary files a/web-app/build/assets/AddTierConfiguration-BJ7D3jgf.js.gz and /dev/null differ diff --git a/web-app/build/assets/AddTierConfiguration-BuE8PwSH.js.gz b/web-app/build/assets/AddTierConfiguration-BuE8PwSH.js.gz new file mode 100644 index 0000000000..4f569814d7 Binary files /dev/null and b/web-app/build/assets/AddTierConfiguration-BuE8PwSH.js.gz differ diff --git a/web-app/build/assets/AreaChart-CJB8ZV2t.js.gz b/web-app/build/assets/AreaChart-CJB8ZV2t.js.gz new file mode 100644 index 0000000000..e15d5eac67 Binary files /dev/null and b/web-app/build/assets/AreaChart-CJB8ZV2t.js.gz differ diff --git a/web-app/build/assets/AreaChart-zCP813HQ.js.gz b/web-app/build/assets/AreaChart-zCP813HQ.js.gz deleted file mode 100644 index e6694d9328..0000000000 Binary files a/web-app/build/assets/AreaChart-zCP813HQ.js.gz and /dev/null differ diff --git a/web-app/build/assets/AutoColorIcon-Bv8QChoN.js.gz b/web-app/build/assets/AutoColorIcon-Bv8QChoN.js.gz new file mode 100644 index 0000000000..3ca5fc80aa Binary files /dev/null and b/web-app/build/assets/AutoColorIcon-Bv8QChoN.js.gz differ diff --git a/web-app/build/assets/AutoColorIcon-CyLR-j5c.js.gz b/web-app/build/assets/AutoColorIcon-CyLR-j5c.js.gz deleted file mode 100644 index f65e117720..0000000000 Binary files a/web-app/build/assets/AutoColorIcon-CyLR-j5c.js.gz and /dev/null differ diff --git a/web-app/build/assets/BarChart-CIajBuR1.js.gz b/web-app/build/assets/BarChart-CIajBuR1.js.gz deleted file mode 100644 index 9ebdc75282..0000000000 Binary files a/web-app/build/assets/BarChart-CIajBuR1.js.gz and /dev/null differ diff --git a/web-app/build/assets/BarChart-CRATT37p.js.gz b/web-app/build/assets/BarChart-CRATT37p.js.gz new file mode 100644 index 0000000000..b19111b6b5 Binary files /dev/null and b/web-app/build/assets/BarChart-CRATT37p.js.gz differ diff --git a/web-app/build/assets/BrowserHandler-CDKwNqVL.js.gz b/web-app/build/assets/BrowserHandler-CDKwNqVL.js.gz deleted file mode 100644 index 92506c0a63..0000000000 Binary files a/web-app/build/assets/BrowserHandler-CDKwNqVL.js.gz and /dev/null differ diff --git a/web-app/build/assets/BrowserHandler-D-k1nYJ-.js.gz b/web-app/build/assets/BrowserHandler-D-k1nYJ-.js.gz new file mode 100644 index 0000000000..b7b4923c33 Binary files /dev/null and b/web-app/build/assets/BrowserHandler-D-k1nYJ-.js.gz differ diff --git a/web-app/build/assets/BucketDetails-BG5xuh3l.js.gz b/web-app/build/assets/BucketDetails-BG5xuh3l.js.gz deleted file mode 100644 index e756e1dea0..0000000000 Binary files a/web-app/build/assets/BucketDetails-BG5xuh3l.js.gz and /dev/null differ diff --git a/web-app/build/assets/BucketDetails-BLkLtaCm.js.gz b/web-app/build/assets/BucketDetails-BLkLtaCm.js.gz new file mode 100644 index 0000000000..58f265bd1e Binary files /dev/null and b/web-app/build/assets/BucketDetails-BLkLtaCm.js.gz differ diff --git a/web-app/build/assets/BucketEventsPanel-B9GQ4sFO.js.gz b/web-app/build/assets/BucketEventsPanel-B9GQ4sFO.js.gz new file mode 100644 index 0000000000..cafe2d866e Binary files /dev/null and b/web-app/build/assets/BucketEventsPanel-B9GQ4sFO.js.gz differ diff --git a/web-app/build/assets/BucketEventsPanel-DDkMGGY3.js.gz b/web-app/build/assets/BucketEventsPanel-DDkMGGY3.js.gz deleted file mode 100644 index ccc70c48f1..0000000000 Binary files a/web-app/build/assets/BucketEventsPanel-DDkMGGY3.js.gz and /dev/null differ diff --git a/web-app/build/assets/BucketLifecyclePanel-CBHlM5Az.js.gz b/web-app/build/assets/BucketLifecyclePanel-CBHlM5Az.js.gz new file mode 100644 index 0000000000..fa55755285 Binary files /dev/null and b/web-app/build/assets/BucketLifecyclePanel-CBHlM5Az.js.gz differ diff --git a/web-app/build/assets/BucketLifecyclePanel-k6Pw5AOk.js.gz b/web-app/build/assets/BucketLifecyclePanel-k6Pw5AOk.js.gz deleted file mode 100644 index ceec4f00c1..0000000000 Binary files a/web-app/build/assets/BucketLifecyclePanel-k6Pw5AOk.js.gz and /dev/null differ diff --git a/web-app/build/assets/BucketReplicationPanel-CWWnFN_f.js.gz b/web-app/build/assets/BucketReplicationPanel-CWWnFN_f.js.gz new file mode 100644 index 0000000000..8b127cf841 Binary files /dev/null and b/web-app/build/assets/BucketReplicationPanel-CWWnFN_f.js.gz differ diff --git a/web-app/build/assets/BucketReplicationPanel-CymneQ1W.js.gz b/web-app/build/assets/BucketReplicationPanel-CymneQ1W.js.gz deleted file mode 100644 index f8d87f5163..0000000000 Binary files a/web-app/build/assets/BucketReplicationPanel-CymneQ1W.js.gz and /dev/null differ diff --git a/web-app/build/assets/BucketSummaryPanel-CDfhelpn.js.gz b/web-app/build/assets/BucketSummaryPanel-CDfhelpn.js.gz deleted file mode 100644 index 4a8527c53b..0000000000 Binary files a/web-app/build/assets/BucketSummaryPanel-CDfhelpn.js.gz and /dev/null differ diff --git a/web-app/build/assets/BucketSummaryPanel-D9GKk7xT.js.gz b/web-app/build/assets/BucketSummaryPanel-D9GKk7xT.js.gz new file mode 100644 index 0000000000..bfc0c78be2 Binary files /dev/null and b/web-app/build/assets/BucketSummaryPanel-D9GKk7xT.js.gz differ diff --git a/web-app/build/assets/BucketTags-BHW95ewQ.js.gz b/web-app/build/assets/BucketTags-BHW95ewQ.js.gz deleted file mode 100644 index af85ecd731..0000000000 Binary files a/web-app/build/assets/BucketTags-BHW95ewQ.js.gz and /dev/null differ diff --git a/web-app/build/assets/BucketTags-DVkfTKoy.js.gz b/web-app/build/assets/BucketTags-DVkfTKoy.js.gz new file mode 100644 index 0000000000..c3ca22e083 Binary files /dev/null and b/web-app/build/assets/BucketTags-DVkfTKoy.js.gz differ diff --git a/web-app/build/assets/Buckets-4U_13U3d.js.gz b/web-app/build/assets/Buckets-4U_13U3d.js.gz new file mode 100644 index 0000000000..12374a5d20 Binary files /dev/null and b/web-app/build/assets/Buckets-4U_13U3d.js.gz differ diff --git a/web-app/build/assets/Buckets-C0SCSpcP.js.gz b/web-app/build/assets/Buckets-C0SCSpcP.js.gz deleted file mode 100644 index 30a0dcec4e..0000000000 Binary files a/web-app/build/assets/Buckets-C0SCSpcP.js.gz and /dev/null differ diff --git a/web-app/build/assets/BulkAddToGroup-73yO1uwE.js.gz b/web-app/build/assets/BulkAddToGroup-73yO1uwE.js.gz deleted file mode 100644 index dd69439587..0000000000 Binary files a/web-app/build/assets/BulkAddToGroup-73yO1uwE.js.gz and /dev/null differ diff --git a/web-app/build/assets/BulkAddToGroup-Bj7vO_Dl.js.gz b/web-app/build/assets/BulkAddToGroup-Bj7vO_Dl.js.gz new file mode 100644 index 0000000000..cc2d60008b Binary files /dev/null and b/web-app/build/assets/BulkAddToGroup-Bj7vO_Dl.js.gz differ diff --git a/web-app/build/assets/CodeMirrorWrapper-DbQgpRNS.js.gz b/web-app/build/assets/CodeMirrorWrapper-DbQgpRNS.js.gz new file mode 100644 index 0000000000..a35233e7ea Binary files /dev/null and b/web-app/build/assets/CodeMirrorWrapper-DbQgpRNS.js.gz differ diff --git a/web-app/build/assets/CodeMirrorWrapper-i-x1llxW.js.gz b/web-app/build/assets/CodeMirrorWrapper-i-x1llxW.js.gz deleted file mode 100644 index 7e69bcc1c8..0000000000 Binary files a/web-app/build/assets/CodeMirrorWrapper-i-x1llxW.js.gz and /dev/null differ diff --git a/web-app/build/assets/ConfMySql-C7ZxrkIf.js.gz b/web-app/build/assets/ConfMySql-C7ZxrkIf.js.gz deleted file mode 100644 index 07a8974922..0000000000 Binary files a/web-app/build/assets/ConfMySql-C7ZxrkIf.js.gz and /dev/null differ diff --git a/web-app/build/assets/ConfMySql-T-2l8NyU.js.gz b/web-app/build/assets/ConfMySql-T-2l8NyU.js.gz new file mode 100644 index 0000000000..aa5d00f3cb Binary files /dev/null and b/web-app/build/assets/ConfMySql-T-2l8NyU.js.gz differ diff --git a/web-app/build/assets/ConfPostgres-BZC23X6U.js.gz b/web-app/build/assets/ConfPostgres-BZC23X6U.js.gz new file mode 100644 index 0000000000..9b7f8c8713 Binary files /dev/null and b/web-app/build/assets/ConfPostgres-BZC23X6U.js.gz differ diff --git a/web-app/build/assets/ConfPostgres-D5VbchZT.js.gz b/web-app/build/assets/ConfPostgres-D5VbchZT.js.gz deleted file mode 100644 index ffa4a1d77a..0000000000 Binary files a/web-app/build/assets/ConfPostgres-D5VbchZT.js.gz and /dev/null differ diff --git a/web-app/build/assets/ConfTargetGeneric-Bc_p3S8s.js.gz b/web-app/build/assets/ConfTargetGeneric-Bc_p3S8s.js.gz new file mode 100644 index 0000000000..52a4fd4339 Binary files /dev/null and b/web-app/build/assets/ConfTargetGeneric-Bc_p3S8s.js.gz differ diff --git a/web-app/build/assets/ConfTargetGeneric-BmVQja2I.js.gz b/web-app/build/assets/ConfTargetGeneric-BmVQja2I.js.gz deleted file mode 100644 index 236e84695d..0000000000 Binary files a/web-app/build/assets/ConfTargetGeneric-BmVQja2I.js.gz and /dev/null differ diff --git a/web-app/build/assets/ConfigurationOptions-DgS_9w3X.js.gz b/web-app/build/assets/ConfigurationOptions-DgS_9w3X.js.gz new file mode 100644 index 0000000000..a0c4a45acf Binary files /dev/null and b/web-app/build/assets/ConfigurationOptions-DgS_9w3X.js.gz differ diff --git a/web-app/build/assets/ConfigurationOptions-lbs_mARw.js.gz b/web-app/build/assets/ConfigurationOptions-lbs_mARw.js.gz deleted file mode 100644 index d8ce8ecf4d..0000000000 Binary files a/web-app/build/assets/ConfigurationOptions-lbs_mARw.js.gz and /dev/null differ diff --git a/web-app/build/assets/CreatePathModal-DAKurITA.js.gz b/web-app/build/assets/CreatePathModal-DAKurITA.js.gz deleted file mode 100644 index df3f5b163e..0000000000 Binary files a/web-app/build/assets/CreatePathModal-DAKurITA.js.gz and /dev/null differ diff --git a/web-app/build/assets/CreatePathModal-DFkFJkiT.js.gz b/web-app/build/assets/CreatePathModal-DFkFJkiT.js.gz new file mode 100644 index 0000000000..ead3b73d19 Binary files /dev/null and b/web-app/build/assets/CreatePathModal-DFkFJkiT.js.gz differ diff --git a/web-app/build/assets/Dashboard-Bol6jSI9.js.gz b/web-app/build/assets/Dashboard-Bol6jSI9.js.gz deleted file mode 100644 index 5d115efa79..0000000000 Binary files a/web-app/build/assets/Dashboard-Bol6jSI9.js.gz and /dev/null differ diff --git a/web-app/build/assets/Dashboard-t0uxa2v6.js.gz b/web-app/build/assets/Dashboard-t0uxa2v6.js.gz new file mode 100644 index 0000000000..93787f0a24 Binary files /dev/null and b/web-app/build/assets/Dashboard-t0uxa2v6.js.gz differ diff --git a/web-app/build/assets/DateRangeSelector-BwhdXPv2.js.gz b/web-app/build/assets/DateRangeSelector-BwhdXPv2.js.gz deleted file mode 100644 index fe5e065e84..0000000000 Binary files a/web-app/build/assets/DateRangeSelector-BwhdXPv2.js.gz and /dev/null differ diff --git a/web-app/build/assets/DateRangeSelector-Cfk1c6B7.js.gz b/web-app/build/assets/DateRangeSelector-Cfk1c6B7.js.gz new file mode 100644 index 0000000000..35b462146f Binary files /dev/null and b/web-app/build/assets/DateRangeSelector-Cfk1c6B7.js.gz differ diff --git a/web-app/build/assets/DeleteAccessRule-BJb2KA0S.js.gz b/web-app/build/assets/DeleteAccessRule-BJb2KA0S.js.gz new file mode 100644 index 0000000000..91805841c5 Binary files /dev/null and b/web-app/build/assets/DeleteAccessRule-BJb2KA0S.js.gz differ diff --git a/web-app/build/assets/DeleteAccessRule-BWDrobpZ.js.gz b/web-app/build/assets/DeleteAccessRule-BWDrobpZ.js.gz deleted file mode 100644 index c41e0a6ecd..0000000000 Binary files a/web-app/build/assets/DeleteAccessRule-BWDrobpZ.js.gz and /dev/null differ diff --git a/web-app/build/assets/DeleteBucket-D3N4sJuT.js.gz b/web-app/build/assets/DeleteBucket-D3N4sJuT.js.gz deleted file mode 100644 index dfbf222086..0000000000 Binary files a/web-app/build/assets/DeleteBucket-D3N4sJuT.js.gz and /dev/null differ diff --git a/web-app/build/assets/DeleteBucket-DqpO5cQO.js.gz b/web-app/build/assets/DeleteBucket-DqpO5cQO.js.gz new file mode 100644 index 0000000000..d3113b92f5 Binary files /dev/null and b/web-app/build/assets/DeleteBucket-DqpO5cQO.js.gz differ diff --git a/web-app/build/assets/DeleteBucketTagModal-DXNNZheI.js.gz b/web-app/build/assets/DeleteBucketTagModal-DXNNZheI.js.gz new file mode 100644 index 0000000000..43a8cc8978 Binary files /dev/null and b/web-app/build/assets/DeleteBucketTagModal-DXNNZheI.js.gz differ diff --git a/web-app/build/assets/DeleteBucketTagModal-DtxsKyNP.js.gz b/web-app/build/assets/DeleteBucketTagModal-DtxsKyNP.js.gz deleted file mode 100644 index 488d0a425d..0000000000 Binary files a/web-app/build/assets/DeleteBucketTagModal-DtxsKyNP.js.gz and /dev/null differ diff --git a/web-app/build/assets/DeleteEvent-CVC-Sfnb.js.gz b/web-app/build/assets/DeleteEvent-CVC-Sfnb.js.gz new file mode 100644 index 0000000000..e101f7a02d Binary files /dev/null and b/web-app/build/assets/DeleteEvent-CVC-Sfnb.js.gz differ diff --git a/web-app/build/assets/DeleteEvent-D_IIWYzl.js.gz b/web-app/build/assets/DeleteEvent-D_IIWYzl.js.gz deleted file mode 100644 index c42b325347..0000000000 Binary files a/web-app/build/assets/DeleteEvent-D_IIWYzl.js.gz and /dev/null differ diff --git a/web-app/build/assets/DeleteGroup-Boqww4m-.js.gz b/web-app/build/assets/DeleteGroup-Boqww4m-.js.gz deleted file mode 100644 index 5852c2ee92..0000000000 Binary files a/web-app/build/assets/DeleteGroup-Boqww4m-.js.gz and /dev/null differ diff --git a/web-app/build/assets/DeleteGroup-C6XpJJFC.js.gz b/web-app/build/assets/DeleteGroup-C6XpJJFC.js.gz new file mode 100644 index 0000000000..3c1c9107d3 Binary files /dev/null and b/web-app/build/assets/DeleteGroup-C6XpJJFC.js.gz differ diff --git a/web-app/build/assets/DeleteIDPConfigurationModal-BUqQFuvl.js.gz b/web-app/build/assets/DeleteIDPConfigurationModal-BUqQFuvl.js.gz new file mode 100644 index 0000000000..de5fa4c62b Binary files /dev/null and b/web-app/build/assets/DeleteIDPConfigurationModal-BUqQFuvl.js.gz differ diff --git a/web-app/build/assets/DeleteIDPConfigurationModal-H6kXSzcg.js.gz b/web-app/build/assets/DeleteIDPConfigurationModal-H6kXSzcg.js.gz deleted file mode 100644 index c0d795f243..0000000000 Binary files a/web-app/build/assets/DeleteIDPConfigurationModal-H6kXSzcg.js.gz and /dev/null differ diff --git a/web-app/build/assets/DeleteMultipleObjects-BRMgaYUw.js.gz b/web-app/build/assets/DeleteMultipleObjects-BRMgaYUw.js.gz new file mode 100644 index 0000000000..414146dd24 Binary files /dev/null and b/web-app/build/assets/DeleteMultipleObjects-BRMgaYUw.js.gz differ diff --git a/web-app/build/assets/DeleteMultipleObjects-DdXM1WaX.js.gz b/web-app/build/assets/DeleteMultipleObjects-DdXM1WaX.js.gz deleted file mode 100644 index 2c74285e17..0000000000 Binary files a/web-app/build/assets/DeleteMultipleObjects-DdXM1WaX.js.gz and /dev/null differ diff --git a/web-app/build/assets/DeletePolicy-B2ON5a8t.js.gz b/web-app/build/assets/DeletePolicy-B2ON5a8t.js.gz deleted file mode 100644 index d92f1d0d23..0000000000 Binary files a/web-app/build/assets/DeletePolicy-B2ON5a8t.js.gz and /dev/null differ diff --git a/web-app/build/assets/DeletePolicy-CJUZIoHu.js.gz b/web-app/build/assets/DeletePolicy-CJUZIoHu.js.gz new file mode 100644 index 0000000000..5c0c9ba3eb Binary files /dev/null and b/web-app/build/assets/DeletePolicy-CJUZIoHu.js.gz differ diff --git a/web-app/build/assets/DeleteReplicationRule-Bwkls0Ky.js.gz b/web-app/build/assets/DeleteReplicationRule-Bwkls0Ky.js.gz new file mode 100644 index 0000000000..44659cfd44 Binary files /dev/null and b/web-app/build/assets/DeleteReplicationRule-Bwkls0Ky.js.gz differ diff --git a/web-app/build/assets/DeleteReplicationRule-FzNZWXKh.js.gz b/web-app/build/assets/DeleteReplicationRule-FzNZWXKh.js.gz deleted file mode 100644 index 3c542baaad..0000000000 Binary files a/web-app/build/assets/DeleteReplicationRule-FzNZWXKh.js.gz and /dev/null differ diff --git a/web-app/build/assets/DeleteServiceAccount-BZLYI-qP.js.gz b/web-app/build/assets/DeleteServiceAccount-BZLYI-qP.js.gz new file mode 100644 index 0000000000..74b3f41c97 Binary files /dev/null and b/web-app/build/assets/DeleteServiceAccount-BZLYI-qP.js.gz differ diff --git a/web-app/build/assets/DeleteServiceAccount-CSZizX-3.js.gz b/web-app/build/assets/DeleteServiceAccount-CSZizX-3.js.gz deleted file mode 100644 index e37d4fb95b..0000000000 Binary files a/web-app/build/assets/DeleteServiceAccount-CSZizX-3.js.gz and /dev/null differ diff --git a/web-app/build/assets/DistributedOnly-DBj6BfGe.js.gz b/web-app/build/assets/DistributedOnly-DBj6BfGe.js.gz deleted file mode 100644 index 483190621b..0000000000 Binary files a/web-app/build/assets/DistributedOnly-DBj6BfGe.js.gz and /dev/null differ diff --git a/web-app/build/assets/DistributedOnly-DsDvS265.js.gz b/web-app/build/assets/DistributedOnly-DsDvS265.js.gz new file mode 100644 index 0000000000..0366fd94a6 Binary files /dev/null and b/web-app/build/assets/DistributedOnly-DsDvS265.js.gz differ diff --git a/web-app/build/assets/EditAccessRule-BwKcRLJt.js.gz b/web-app/build/assets/EditAccessRule-BwKcRLJt.js.gz new file mode 100644 index 0000000000..1dbfa966ee Binary files /dev/null and b/web-app/build/assets/EditAccessRule-BwKcRLJt.js.gz differ diff --git a/web-app/build/assets/EditAccessRule-xaPbwfL6.js.gz b/web-app/build/assets/EditAccessRule-xaPbwfL6.js.gz deleted file mode 100644 index 5ff5167c89..0000000000 Binary files a/web-app/build/assets/EditAccessRule-xaPbwfL6.js.gz and /dev/null differ diff --git a/web-app/build/assets/EditBucketReplication-CjKMTg4b.js.gz b/web-app/build/assets/EditBucketReplication-CjKMTg4b.js.gz new file mode 100644 index 0000000000..d97094a6bd Binary files /dev/null and b/web-app/build/assets/EditBucketReplication-CjKMTg4b.js.gz differ diff --git a/web-app/build/assets/EditBucketReplication-VsvjtcJL.js.gz b/web-app/build/assets/EditBucketReplication-VsvjtcJL.js.gz deleted file mode 100644 index 16d681c354..0000000000 Binary files a/web-app/build/assets/EditBucketReplication-VsvjtcJL.js.gz and /dev/null differ diff --git a/web-app/build/assets/EditReplicationModal-BazVqm1P.js.gz b/web-app/build/assets/EditReplicationModal-BazVqm1P.js.gz new file mode 100644 index 0000000000..d310ff88bc Binary files /dev/null and b/web-app/build/assets/EditReplicationModal-BazVqm1P.js.gz differ diff --git a/web-app/build/assets/EditReplicationModal-JEI9NIRb.js.gz b/web-app/build/assets/EditReplicationModal-JEI9NIRb.js.gz deleted file mode 100644 index 64ec93d2ab..0000000000 Binary files a/web-app/build/assets/EditReplicationModal-JEI9NIRb.js.gz and /dev/null differ diff --git a/web-app/build/assets/EnableBucketEncryption-ByGaW4mV.js.gz b/web-app/build/assets/EnableBucketEncryption-ByGaW4mV.js.gz new file mode 100644 index 0000000000..26fcd292c5 Binary files /dev/null and b/web-app/build/assets/EnableBucketEncryption-ByGaW4mV.js.gz differ diff --git a/web-app/build/assets/EnableBucketEncryption-ChayOvNm.js.gz b/web-app/build/assets/EnableBucketEncryption-ChayOvNm.js.gz deleted file mode 100644 index 00f93d488d..0000000000 Binary files a/web-app/build/assets/EnableBucketEncryption-ChayOvNm.js.gz and /dev/null differ diff --git a/web-app/build/assets/EnableQuota-B_FiDxw8.js.gz b/web-app/build/assets/EnableQuota-B_FiDxw8.js.gz new file mode 100644 index 0000000000..bcaf1ddf75 Binary files /dev/null and b/web-app/build/assets/EnableQuota-B_FiDxw8.js.gz differ diff --git a/web-app/build/assets/EnableQuota-D3-Bl8wU.js.gz b/web-app/build/assets/EnableQuota-D3-Bl8wU.js.gz deleted file mode 100644 index fc177697b8..0000000000 Binary files a/web-app/build/assets/EnableQuota-D3-Bl8wU.js.gz and /dev/null differ diff --git a/web-app/build/assets/EnableVersioningModal-Dp5f318q.js.gz b/web-app/build/assets/EnableVersioningModal-Dp5f318q.js.gz new file mode 100644 index 0000000000..a561061f44 Binary files /dev/null and b/web-app/build/assets/EnableVersioningModal-Dp5f318q.js.gz differ diff --git a/web-app/build/assets/EnableVersioningModal-VuFTOzvD.js.gz b/web-app/build/assets/EnableVersioningModal-VuFTOzvD.js.gz deleted file mode 100644 index 5386627624..0000000000 Binary files a/web-app/build/assets/EnableVersioningModal-VuFTOzvD.js.gz and /dev/null differ diff --git a/web-app/build/assets/ErrorLogs-C2lPumhv.js.gz b/web-app/build/assets/ErrorLogs-C2lPumhv.js.gz deleted file mode 100644 index 9923b84de5..0000000000 Binary files a/web-app/build/assets/ErrorLogs-C2lPumhv.js.gz and /dev/null differ diff --git a/web-app/build/assets/ErrorLogs-CNsjKFE1.js.gz b/web-app/build/assets/ErrorLogs-CNsjKFE1.js.gz new file mode 100644 index 0000000000..804db8f71e Binary files /dev/null and b/web-app/build/assets/ErrorLogs-CNsjKFE1.js.gz differ diff --git a/web-app/build/assets/EventDestinations-6m553JPb.js.gz b/web-app/build/assets/EventDestinations-6m553JPb.js.gz new file mode 100644 index 0000000000..06987b4585 Binary files /dev/null and b/web-app/build/assets/EventDestinations-6m553JPb.js.gz differ diff --git a/web-app/build/assets/EventDestinations-CXMtA9n9.js.gz b/web-app/build/assets/EventDestinations-CXMtA9n9.js.gz deleted file mode 100644 index 4afe3b08b8..0000000000 Binary files a/web-app/build/assets/EventDestinations-CXMtA9n9.js.gz and /dev/null differ diff --git a/web-app/build/assets/EventTypeSelector-DnlNXTjf.js.gz b/web-app/build/assets/EventTypeSelector-DnlNXTjf.js.gz deleted file mode 100644 index 39e41d8c25..0000000000 Binary files a/web-app/build/assets/EventTypeSelector-DnlNXTjf.js.gz and /dev/null differ diff --git a/web-app/build/assets/EventTypeSelector-to6UsND7.js.gz b/web-app/build/assets/EventTypeSelector-to6UsND7.js.gz new file mode 100644 index 0000000000..30c6fdb588 Binary files /dev/null and b/web-app/build/assets/EventTypeSelector-to6UsND7.js.gz differ diff --git a/web-app/build/assets/Groups-DM7SeNJd.js.gz b/web-app/build/assets/Groups-DM7SeNJd.js.gz deleted file mode 100644 index 118962e6fb..0000000000 Binary files a/web-app/build/assets/Groups-DM7SeNJd.js.gz and /dev/null differ diff --git a/web-app/build/assets/Groups-vbrY-nu9.js.gz b/web-app/build/assets/Groups-vbrY-nu9.js.gz new file mode 100644 index 0000000000..0a52063795 Binary files /dev/null and b/web-app/build/assets/Groups-vbrY-nu9.js.gz differ diff --git a/web-app/build/assets/GroupsDetails-Bu2xgwr1.js.gz b/web-app/build/assets/GroupsDetails-Bu2xgwr1.js.gz deleted file mode 100644 index fa4219c2cd..0000000000 Binary files a/web-app/build/assets/GroupsDetails-Bu2xgwr1.js.gz and /dev/null differ diff --git a/web-app/build/assets/GroupsDetails-D88j9xrt.js.gz b/web-app/build/assets/GroupsDetails-D88j9xrt.js.gz new file mode 100644 index 0000000000..644abcb847 Binary files /dev/null and b/web-app/build/assets/GroupsDetails-D88j9xrt.js.gz differ diff --git a/web-app/build/assets/GroupsSelectors-C1j4ewnc.js.gz b/web-app/build/assets/GroupsSelectors-C1j4ewnc.js.gz deleted file mode 100644 index 2c31981be3..0000000000 Binary files a/web-app/build/assets/GroupsSelectors-C1j4ewnc.js.gz and /dev/null differ diff --git a/web-app/build/assets/GroupsSelectors-Dn8wrrpt.js.gz b/web-app/build/assets/GroupsSelectors-Dn8wrrpt.js.gz new file mode 100644 index 0000000000..a1d6cc54c7 Binary files /dev/null and b/web-app/build/assets/GroupsSelectors-Dn8wrrpt.js.gz differ diff --git a/web-app/build/assets/HealthInfo-BQpVArsg.js.gz b/web-app/build/assets/HealthInfo-BQpVArsg.js.gz new file mode 100644 index 0000000000..97489ba57b Binary files /dev/null and b/web-app/build/assets/HealthInfo-BQpVArsg.js.gz differ diff --git a/web-app/build/assets/HealthInfo-BwkovdLE.js.gz b/web-app/build/assets/HealthInfo-BwkovdLE.js.gz deleted file mode 100644 index 10a8ef9292..0000000000 Binary files a/web-app/build/assets/HealthInfo-BwkovdLE.js.gz and /dev/null differ diff --git a/web-app/build/assets/IDPLDAPConfigurationDetails-BSt-_TEO.js.gz b/web-app/build/assets/IDPLDAPConfigurationDetails-BSt-_TEO.js.gz new file mode 100644 index 0000000000..cc3744c0f4 Binary files /dev/null and b/web-app/build/assets/IDPLDAPConfigurationDetails-BSt-_TEO.js.gz differ diff --git a/web-app/build/assets/IDPLDAPConfigurationDetails-CymkmrWF.js.gz b/web-app/build/assets/IDPLDAPConfigurationDetails-CymkmrWF.js.gz deleted file mode 100644 index cb1a93855a..0000000000 Binary files a/web-app/build/assets/IDPLDAPConfigurationDetails-CymkmrWF.js.gz and /dev/null differ diff --git a/web-app/build/assets/IDPOpenIDConfigurationDetails-CXqq5rgx.js.gz b/web-app/build/assets/IDPOpenIDConfigurationDetails-CXqq5rgx.js.gz deleted file mode 100644 index f4195b7a57..0000000000 Binary files a/web-app/build/assets/IDPOpenIDConfigurationDetails-CXqq5rgx.js.gz and /dev/null differ diff --git a/web-app/build/assets/IDPOpenIDConfigurationDetails-DEPy7PJK.js.gz b/web-app/build/assets/IDPOpenIDConfigurationDetails-DEPy7PJK.js.gz new file mode 100644 index 0000000000..dac7fca9ad Binary files /dev/null and b/web-app/build/assets/IDPOpenIDConfigurationDetails-DEPy7PJK.js.gz differ diff --git a/web-app/build/assets/IDPOpenIDConfigurations-CHrI4yR6.js.gz b/web-app/build/assets/IDPOpenIDConfigurations-CHrI4yR6.js.gz new file mode 100644 index 0000000000..5c5dd80dbf Binary files /dev/null and b/web-app/build/assets/IDPOpenIDConfigurations-CHrI4yR6.js.gz differ diff --git a/web-app/build/assets/IDPOpenIDConfigurations-DKJ5kc6X.js.gz b/web-app/build/assets/IDPOpenIDConfigurations-DKJ5kc6X.js.gz deleted file mode 100644 index cf197c45c8..0000000000 Binary files a/web-app/build/assets/IDPOpenIDConfigurations-DKJ5kc6X.js.gz and /dev/null differ diff --git a/web-app/build/assets/IconsScreen-BcZASjIe.js.gz b/web-app/build/assets/IconsScreen-BcZASjIe.js.gz deleted file mode 100644 index d447962683..0000000000 Binary files a/web-app/build/assets/IconsScreen-BcZASjIe.js.gz and /dev/null differ diff --git a/web-app/build/assets/IconsScreen-C0s-RJ0l.js.gz b/web-app/build/assets/IconsScreen-C0s-RJ0l.js.gz new file mode 100644 index 0000000000..e863da7f60 Binary files /dev/null and b/web-app/build/assets/IconsScreen-C0s-RJ0l.js.gz differ diff --git a/web-app/build/assets/Inspect-C1iMlrb8.js.gz b/web-app/build/assets/Inspect-C1iMlrb8.js.gz deleted file mode 100644 index 8714c3e10c..0000000000 Binary files a/web-app/build/assets/Inspect-C1iMlrb8.js.gz and /dev/null differ diff --git a/web-app/build/assets/Inspect-C_YLSmCL.js.gz b/web-app/build/assets/Inspect-C_YLSmCL.js.gz new file mode 100644 index 0000000000..d25711901e Binary files /dev/null and b/web-app/build/assets/Inspect-C_YLSmCL.js.gz differ diff --git a/web-app/build/assets/KMSHelpbox-CwsR758o.js.gz b/web-app/build/assets/KMSHelpbox-CwsR758o.js.gz new file mode 100644 index 0000000000..e077e461ce Binary files /dev/null and b/web-app/build/assets/KMSHelpbox-CwsR758o.js.gz differ diff --git a/web-app/build/assets/KMSHelpbox-Cy2LhlwA.js.gz b/web-app/build/assets/KMSHelpbox-Cy2LhlwA.js.gz deleted file mode 100644 index 598a2dd035..0000000000 Binary files a/web-app/build/assets/KMSHelpbox-Cy2LhlwA.js.gz and /dev/null differ diff --git a/web-app/build/assets/KMSRoutes-Cj-23LuL.js.gz b/web-app/build/assets/KMSRoutes-Cj-23LuL.js.gz deleted file mode 100644 index 094b9b651d..0000000000 Binary files a/web-app/build/assets/KMSRoutes-Cj-23LuL.js.gz and /dev/null differ diff --git a/web-app/build/assets/KMSRoutes-kQ_GF-va.js.gz b/web-app/build/assets/KMSRoutes-kQ_GF-va.js.gz new file mode 100644 index 0000000000..6390f3981b Binary files /dev/null and b/web-app/build/assets/KMSRoutes-kQ_GF-va.js.gz differ diff --git a/web-app/build/assets/LabelWithIcon-6VX4qbyx.js.gz b/web-app/build/assets/LabelWithIcon-6VX4qbyx.js.gz new file mode 100644 index 0000000000..4d4374c293 Binary files /dev/null and b/web-app/build/assets/LabelWithIcon-6VX4qbyx.js.gz differ diff --git a/web-app/build/assets/LabelWithIcon-BnuiLlcn.js.gz b/web-app/build/assets/LabelWithIcon-BnuiLlcn.js.gz deleted file mode 100644 index 0d065ef6c0..0000000000 Binary files a/web-app/build/assets/LabelWithIcon-BnuiLlcn.js.gz and /dev/null differ diff --git a/web-app/build/assets/License-BSkfeawk.js.gz b/web-app/build/assets/License-BSkfeawk.js.gz new file mode 100644 index 0000000000..6b57c42673 Binary files /dev/null and b/web-app/build/assets/License-BSkfeawk.js.gz differ diff --git a/web-app/build/assets/License-DgW2blgT.js.gz b/web-app/build/assets/License-DgW2blgT.js.gz deleted file mode 100644 index 08d68d3a9c..0000000000 Binary files a/web-app/build/assets/License-DgW2blgT.js.gz and /dev/null differ diff --git a/web-app/build/assets/ListBuckets-By2VxU2q.js.gz b/web-app/build/assets/ListBuckets-By2VxU2q.js.gz new file mode 100644 index 0000000000..f4c546d115 Binary files /dev/null and b/web-app/build/assets/ListBuckets-By2VxU2q.js.gz differ diff --git a/web-app/build/assets/ListBuckets-CQ14jPJq.js.gz b/web-app/build/assets/ListBuckets-CQ14jPJq.js.gz deleted file mode 100644 index 7569c1a334..0000000000 Binary files a/web-app/build/assets/ListBuckets-CQ14jPJq.js.gz and /dev/null differ diff --git a/web-app/build/assets/ListEventDestinations-Cjdnihg8.js.gz b/web-app/build/assets/ListEventDestinations-Cjdnihg8.js.gz new file mode 100644 index 0000000000..b4d0a0f1b9 Binary files /dev/null and b/web-app/build/assets/ListEventDestinations-Cjdnihg8.js.gz differ diff --git a/web-app/build/assets/ListEventDestinations-KDmMAzz4.js.gz b/web-app/build/assets/ListEventDestinations-KDmMAzz4.js.gz deleted file mode 100644 index 390c878859..0000000000 Binary files a/web-app/build/assets/ListEventDestinations-KDmMAzz4.js.gz and /dev/null differ diff --git a/web-app/build/assets/ListKeys-BFhKLcsG.js.gz b/web-app/build/assets/ListKeys-BFhKLcsG.js.gz new file mode 100644 index 0000000000..ac72d4191e Binary files /dev/null and b/web-app/build/assets/ListKeys-BFhKLcsG.js.gz differ diff --git a/web-app/build/assets/ListKeys-oC8hq54a.js.gz b/web-app/build/assets/ListKeys-oC8hq54a.js.gz deleted file mode 100644 index 0c7b0e5144..0000000000 Binary files a/web-app/build/assets/ListKeys-oC8hq54a.js.gz and /dev/null differ diff --git a/web-app/build/assets/ListPolicies-DcoYDoPv.js.gz b/web-app/build/assets/ListPolicies-DcoYDoPv.js.gz deleted file mode 100644 index 4e81ded020..0000000000 Binary files a/web-app/build/assets/ListPolicies-DcoYDoPv.js.gz and /dev/null differ diff --git a/web-app/build/assets/ListPolicies-modRCkL_.js.gz b/web-app/build/assets/ListPolicies-modRCkL_.js.gz new file mode 100644 index 0000000000..e086525dfd Binary files /dev/null and b/web-app/build/assets/ListPolicies-modRCkL_.js.gz differ diff --git a/web-app/build/assets/ListTiersConfiguration-CAl-BQl1.js.gz b/web-app/build/assets/ListTiersConfiguration-CAl-BQl1.js.gz deleted file mode 100644 index bdbf543939..0000000000 Binary files a/web-app/build/assets/ListTiersConfiguration-CAl-BQl1.js.gz and /dev/null differ diff --git a/web-app/build/assets/ListTiersConfiguration-sPa6_hUX.js.gz b/web-app/build/assets/ListTiersConfiguration-sPa6_hUX.js.gz new file mode 100644 index 0000000000..9435d06b61 Binary files /dev/null and b/web-app/build/assets/ListTiersConfiguration-sPa6_hUX.js.gz differ diff --git a/web-app/build/assets/Login-DyW08Qlf.js.gz b/web-app/build/assets/Login-DyW08Qlf.js.gz new file mode 100644 index 0000000000..54bb2ad890 Binary files /dev/null and b/web-app/build/assets/Login-DyW08Qlf.js.gz differ diff --git a/web-app/build/assets/Login-_DDBA0mC.js.gz b/web-app/build/assets/Login-_DDBA0mC.js.gz deleted file mode 100644 index 708d3c08da..0000000000 Binary files a/web-app/build/assets/Login-_DDBA0mC.js.gz and /dev/null differ diff --git a/web-app/build/assets/LoginCallback-CAt8kTBZ.js.gz b/web-app/build/assets/LoginCallback-CAt8kTBZ.js.gz deleted file mode 100644 index 1b2afa380b..0000000000 Binary files a/web-app/build/assets/LoginCallback-CAt8kTBZ.js.gz and /dev/null differ diff --git a/web-app/build/assets/LoginCallback-DaOH2gca.js.gz b/web-app/build/assets/LoginCallback-DaOH2gca.js.gz new file mode 100644 index 0000000000..7f8fd55549 Binary files /dev/null and b/web-app/build/assets/LoginCallback-DaOH2gca.js.gz differ diff --git a/web-app/build/assets/LoginLayout-BIswuiKX.js.gz b/web-app/build/assets/LoginLayout-BIswuiKX.js.gz new file mode 100644 index 0000000000..e7c3ac185f Binary files /dev/null and b/web-app/build/assets/LoginLayout-BIswuiKX.js.gz differ diff --git a/web-app/build/assets/LoginLayout-DOu441RV.js.gz b/web-app/build/assets/LoginLayout-DOu441RV.js.gz deleted file mode 100644 index 0732686a98..0000000000 Binary files a/web-app/build/assets/LoginLayout-DOu441RV.js.gz and /dev/null differ diff --git a/web-app/build/assets/LogoutPage-BHeJ89CI.js.gz b/web-app/build/assets/LogoutPage-BHeJ89CI.js.gz deleted file mode 100644 index cf78e5063c..0000000000 Binary files a/web-app/build/assets/LogoutPage-BHeJ89CI.js.gz and /dev/null differ diff --git a/web-app/build/assets/LogoutPage-EAFfg1L_.js.gz b/web-app/build/assets/LogoutPage-EAFfg1L_.js.gz new file mode 100644 index 0000000000..fbdbe17b37 Binary files /dev/null and b/web-app/build/assets/LogoutPage-EAFfg1L_.js.gz differ diff --git a/web-app/build/assets/LogsSearchMain-BzFBJOPd.js.gz b/web-app/build/assets/LogsSearchMain-BzFBJOPd.js.gz new file mode 100644 index 0000000000..984c243d1f Binary files /dev/null and b/web-app/build/assets/LogsSearchMain-BzFBJOPd.js.gz differ diff --git a/web-app/build/assets/LogsSearchMain-wcYggpFb.js.gz b/web-app/build/assets/LogsSearchMain-wcYggpFb.js.gz deleted file mode 100644 index 6518b7f342..0000000000 Binary files a/web-app/build/assets/LogsSearchMain-wcYggpFb.js.gz and /dev/null differ diff --git a/web-app/build/assets/NotFoundPage-CJwdegF_.js.gz b/web-app/build/assets/NotFoundPage-CJwdegF_.js.gz deleted file mode 100644 index e63eb5d1e3..0000000000 Binary files a/web-app/build/assets/NotFoundPage-CJwdegF_.js.gz and /dev/null differ diff --git a/web-app/build/assets/ObjectBrowser-BHbaKsoa.js.gz b/web-app/build/assets/ObjectBrowser-BHbaKsoa.js.gz deleted file mode 100644 index 5abfc4d246..0000000000 Binary files a/web-app/build/assets/ObjectBrowser-BHbaKsoa.js.gz and /dev/null differ diff --git a/web-app/build/assets/ObjectBrowser-D_s2kwa6.js.gz b/web-app/build/assets/ObjectBrowser-D_s2kwa6.js.gz new file mode 100644 index 0000000000..f76c618a57 Binary files /dev/null and b/web-app/build/assets/ObjectBrowser-D_s2kwa6.js.gz differ diff --git a/web-app/build/assets/ObjectManager-DAAVLn68.js.gz b/web-app/build/assets/ObjectManager-DAAVLn68.js.gz deleted file mode 100644 index 0c846cf508..0000000000 Binary files a/web-app/build/assets/ObjectManager-DAAVLn68.js.gz and /dev/null differ diff --git a/web-app/build/assets/ObjectManager-DoaXz3G4.js.gz b/web-app/build/assets/ObjectManager-DoaXz3G4.js.gz new file mode 100644 index 0000000000..1f9948a870 Binary files /dev/null and b/web-app/build/assets/ObjectManager-DoaXz3G4.js.gz differ diff --git a/web-app/build/assets/PanelTitle-BdSQiRbG.js.gz b/web-app/build/assets/PanelTitle-BdSQiRbG.js.gz new file mode 100644 index 0000000000..d06a83a93d Binary files /dev/null and b/web-app/build/assets/PanelTitle-BdSQiRbG.js.gz differ diff --git a/web-app/build/assets/PanelTitle-DGLY_nT7.js.gz b/web-app/build/assets/PanelTitle-DGLY_nT7.js.gz deleted file mode 100644 index 6bb5e35bd6..0000000000 Binary files a/web-app/build/assets/PanelTitle-DGLY_nT7.js.gz and /dev/null differ diff --git a/web-app/build/assets/Policies-7c2ognVJ.js.gz b/web-app/build/assets/Policies-7c2ognVJ.js.gz new file mode 100644 index 0000000000..94bf0f0c34 Binary files /dev/null and b/web-app/build/assets/Policies-7c2ognVJ.js.gz differ diff --git a/web-app/build/assets/Policies-CYOXtBKe.js.gz b/web-app/build/assets/Policies-CYOXtBKe.js.gz deleted file mode 100644 index 260ff73d23..0000000000 Binary files a/web-app/build/assets/Policies-CYOXtBKe.js.gz and /dev/null differ diff --git a/web-app/build/assets/PolicyDetails-DXNhETb5.js.gz b/web-app/build/assets/PolicyDetails-DXNhETb5.js.gz deleted file mode 100644 index 66398251a1..0000000000 Binary files a/web-app/build/assets/PolicyDetails-DXNhETb5.js.gz and /dev/null differ diff --git a/web-app/build/assets/PolicyDetails-iz7LZYGR.js.gz b/web-app/build/assets/PolicyDetails-iz7LZYGR.js.gz new file mode 100644 index 0000000000..2a8bd0db6e Binary files /dev/null and b/web-app/build/assets/PolicyDetails-iz7LZYGR.js.gz differ diff --git a/web-app/build/assets/PolicySelectors-BZtTkBiq.js.gz b/web-app/build/assets/PolicySelectors-BZtTkBiq.js.gz deleted file mode 100644 index 6194d5e9af..0000000000 Binary files a/web-app/build/assets/PolicySelectors-BZtTkBiq.js.gz and /dev/null differ diff --git a/web-app/build/assets/PolicySelectors-xpVTOowU.js.gz b/web-app/build/assets/PolicySelectors-xpVTOowU.js.gz new file mode 100644 index 0000000000..ca1ab25a33 Binary files /dev/null and b/web-app/build/assets/PolicySelectors-xpVTOowU.js.gz differ diff --git a/web-app/build/assets/Profile-DEr21ICr.js.gz b/web-app/build/assets/Profile-DEr21ICr.js.gz deleted file mode 100644 index 460f71b781..0000000000 Binary files a/web-app/build/assets/Profile-DEr21ICr.js.gz and /dev/null differ diff --git a/web-app/build/assets/Profile-DnJNaZoU.js.gz b/web-app/build/assets/Profile-DnJNaZoU.js.gz new file mode 100644 index 0000000000..1a7d8525cc Binary files /dev/null and b/web-app/build/assets/Profile-DnJNaZoU.js.gz differ diff --git a/web-app/build/assets/ProgressBarWrapper-5HJswR53.js.gz b/web-app/build/assets/ProgressBarWrapper-5HJswR53.js.gz deleted file mode 100644 index 7bd4dc2c36..0000000000 Binary files a/web-app/build/assets/ProgressBarWrapper-5HJswR53.js.gz and /dev/null differ diff --git a/web-app/build/assets/ProgressBarWrapper-RhKoZmVO.js.gz b/web-app/build/assets/ProgressBarWrapper-RhKoZmVO.js.gz new file mode 100644 index 0000000000..adfec765b8 Binary files /dev/null and b/web-app/build/assets/ProgressBarWrapper-RhKoZmVO.js.gz differ diff --git a/web-app/build/assets/QueryMultiSelector-CjbaIknL.js.gz b/web-app/build/assets/QueryMultiSelector-CjbaIknL.js.gz new file mode 100644 index 0000000000..0e74cde805 Binary files /dev/null and b/web-app/build/assets/QueryMultiSelector-CjbaIknL.js.gz differ diff --git a/web-app/build/assets/QueryMultiSelector-DnKdGUOa.js.gz b/web-app/build/assets/QueryMultiSelector-DnKdGUOa.js.gz deleted file mode 100644 index 2d6506bc16..0000000000 Binary files a/web-app/build/assets/QueryMultiSelector-DnKdGUOa.js.gz and /dev/null differ diff --git a/web-app/build/assets/ReportedUsage-BMlRHsfY.js.gz b/web-app/build/assets/ReportedUsage-BMlRHsfY.js.gz deleted file mode 100644 index 5a3c51c4e6..0000000000 Binary files a/web-app/build/assets/ReportedUsage-BMlRHsfY.js.gz and /dev/null differ diff --git a/web-app/build/assets/ReportedUsage-Bf68ojMo.js.gz b/web-app/build/assets/ReportedUsage-Bf68ojMo.js.gz new file mode 100644 index 0000000000..b95eb3743a Binary files /dev/null and b/web-app/build/assets/ReportedUsage-Bf68ojMo.js.gz differ diff --git a/web-app/build/assets/ResetConfigurationModal-CJ-OBOnB.js.gz b/web-app/build/assets/ResetConfigurationModal-CJ-OBOnB.js.gz new file mode 100644 index 0000000000..402471645c Binary files /dev/null and b/web-app/build/assets/ResetConfigurationModal-CJ-OBOnB.js.gz differ diff --git a/web-app/build/assets/ResetConfigurationModal-DzSTLr_P.js.gz b/web-app/build/assets/ResetConfigurationModal-DzSTLr_P.js.gz deleted file mode 100644 index 73891be211..0000000000 Binary files a/web-app/build/assets/ResetConfigurationModal-DzSTLr_P.js.gz and /dev/null differ diff --git a/web-app/build/assets/RewindEnable--5VsXN80.js.gz b/web-app/build/assets/RewindEnable--5VsXN80.js.gz deleted file mode 100644 index b2ae3ccad2..0000000000 Binary files a/web-app/build/assets/RewindEnable--5VsXN80.js.gz and /dev/null differ diff --git a/web-app/build/assets/RewindEnable-BSgG7cLl.js.gz b/web-app/build/assets/RewindEnable-BSgG7cLl.js.gz new file mode 100644 index 0000000000..b5f48e1bb3 Binary files /dev/null and b/web-app/build/assets/RewindEnable-BSgG7cLl.js.gz differ diff --git a/web-app/build/assets/SSOLogin-DMQGL6lx.js.gz b/web-app/build/assets/SSOLogin-DMQGL6lx.js.gz deleted file mode 100644 index d17aae4858..0000000000 Binary files a/web-app/build/assets/SSOLogin-DMQGL6lx.js.gz and /dev/null differ diff --git a/web-app/build/assets/SSOLogin-DiHEr52P.js.gz b/web-app/build/assets/SSOLogin-DiHEr52P.js.gz new file mode 100644 index 0000000000..04beab5fc5 Binary files /dev/null and b/web-app/build/assets/SSOLogin-DiHEr52P.js.gz differ diff --git a/web-app/build/assets/SearchBox-3tiH6Bww.js.gz b/web-app/build/assets/SearchBox-3tiH6Bww.js.gz new file mode 100644 index 0000000000..ad6f64d56b Binary files /dev/null and b/web-app/build/assets/SearchBox-3tiH6Bww.js.gz differ diff --git a/web-app/build/assets/SearchBox-CbpzCSaa.js.gz b/web-app/build/assets/SearchBox-CbpzCSaa.js.gz deleted file mode 100644 index 60bd944a4f..0000000000 Binary files a/web-app/build/assets/SearchBox-CbpzCSaa.js.gz and /dev/null differ diff --git a/web-app/build/assets/SetAccessPolicy-Cxqk8MIw.js.gz b/web-app/build/assets/SetAccessPolicy-Cxqk8MIw.js.gz new file mode 100644 index 0000000000..afe3cb0497 Binary files /dev/null and b/web-app/build/assets/SetAccessPolicy-Cxqk8MIw.js.gz differ diff --git a/web-app/build/assets/SetAccessPolicy-dCPot9qZ.js.gz b/web-app/build/assets/SetAccessPolicy-dCPot9qZ.js.gz deleted file mode 100644 index 946f56e1d1..0000000000 Binary files a/web-app/build/assets/SetAccessPolicy-dCPot9qZ.js.gz and /dev/null differ diff --git a/web-app/build/assets/SetPolicy-Bpy5RHkN.js.gz b/web-app/build/assets/SetPolicy-Bpy5RHkN.js.gz new file mode 100644 index 0000000000..1002b6277f Binary files /dev/null and b/web-app/build/assets/SetPolicy-Bpy5RHkN.js.gz differ diff --git a/web-app/build/assets/SetPolicy-yo5jwq3N.js.gz b/web-app/build/assets/SetPolicy-yo5jwq3N.js.gz deleted file mode 100644 index bd19be7910..0000000000 Binary files a/web-app/build/assets/SetPolicy-yo5jwq3N.js.gz and /dev/null differ diff --git a/web-app/build/assets/SetRetentionConfig-Bs6WPaQN.js.gz b/web-app/build/assets/SetRetentionConfig-Bs6WPaQN.js.gz new file mode 100644 index 0000000000..25d87e887e Binary files /dev/null and b/web-app/build/assets/SetRetentionConfig-Bs6WPaQN.js.gz differ diff --git a/web-app/build/assets/SetRetentionConfig-Ivq37Cwr.js.gz b/web-app/build/assets/SetRetentionConfig-Ivq37Cwr.js.gz deleted file mode 100644 index 2d90b42ef5..0000000000 Binary files a/web-app/build/assets/SetRetentionConfig-Ivq37Cwr.js.gz and /dev/null differ diff --git a/web-app/build/assets/SiteReplication-B3BobPzE.js.gz b/web-app/build/assets/SiteReplication-B3BobPzE.js.gz deleted file mode 100644 index 68e9972efd..0000000000 Binary files a/web-app/build/assets/SiteReplication-B3BobPzE.js.gz and /dev/null differ diff --git a/web-app/build/assets/SiteReplication-Cg6cg6iC.js.gz b/web-app/build/assets/SiteReplication-Cg6cg6iC.js.gz new file mode 100644 index 0000000000..2e8aecaa15 Binary files /dev/null and b/web-app/build/assets/SiteReplication-Cg6cg6iC.js.gz differ diff --git a/web-app/build/assets/SiteReplicationStatus-BhRfmzI0.js.gz b/web-app/build/assets/SiteReplicationStatus-BhRfmzI0.js.gz new file mode 100644 index 0000000000..5154dff57a Binary files /dev/null and b/web-app/build/assets/SiteReplicationStatus-BhRfmzI0.js.gz differ diff --git a/web-app/build/assets/SiteReplicationStatus-Cn2knlN4.js.gz b/web-app/build/assets/SiteReplicationStatus-Cn2knlN4.js.gz deleted file mode 100644 index 83f4c23df4..0000000000 Binary files a/web-app/build/assets/SiteReplicationStatus-Cn2knlN4.js.gz and /dev/null differ diff --git a/web-app/build/assets/Speedtest-84oqDCsr.js.gz b/web-app/build/assets/Speedtest-84oqDCsr.js.gz deleted file mode 100644 index 5176524012..0000000000 Binary files a/web-app/build/assets/Speedtest-84oqDCsr.js.gz and /dev/null differ diff --git a/web-app/build/assets/Speedtest-CJTAVhk6.js.gz b/web-app/build/assets/Speedtest-CJTAVhk6.js.gz new file mode 100644 index 0000000000..91581cbfab Binary files /dev/null and b/web-app/build/assets/Speedtest-CJTAVhk6.js.gz differ diff --git a/web-app/build/assets/Status-DDq0k-E8.js.gz b/web-app/build/assets/Status-DDq0k-E8.js.gz deleted file mode 100644 index d49e1fbe4e..0000000000 Binary files a/web-app/build/assets/Status-DDq0k-E8.js.gz and /dev/null differ diff --git a/web-app/build/assets/Status-DsSSS-q_.js.gz b/web-app/build/assets/Status-DsSSS-q_.js.gz new file mode 100644 index 0000000000..c8904b017b Binary files /dev/null and b/web-app/build/assets/Status-DsSSS-q_.js.gz differ diff --git a/web-app/build/assets/StatusCountCard-BT60Qd9Q.js.gz b/web-app/build/assets/StatusCountCard-BT60Qd9Q.js.gz new file mode 100644 index 0000000000..16df0be440 Binary files /dev/null and b/web-app/build/assets/StatusCountCard-BT60Qd9Q.js.gz differ diff --git a/web-app/build/assets/StatusCountCard-BbX0WeKz.js.gz b/web-app/build/assets/StatusCountCard-BbX0WeKz.js.gz deleted file mode 100644 index baf4d293a2..0000000000 Binary files a/web-app/build/assets/StatusCountCard-BbX0WeKz.js.gz and /dev/null differ diff --git a/web-app/build/assets/TierTypeSelector-BH4UFy5I.js.gz b/web-app/build/assets/TierTypeSelector-BH4UFy5I.js.gz deleted file mode 100644 index 4b357955bb..0000000000 Binary files a/web-app/build/assets/TierTypeSelector-BH4UFy5I.js.gz and /dev/null differ diff --git a/web-app/build/assets/TierTypeSelector-D9jARiX2.js.gz b/web-app/build/assets/TierTypeSelector-D9jARiX2.js.gz new file mode 100644 index 0000000000..60deaedded Binary files /dev/null and b/web-app/build/assets/TierTypeSelector-D9jARiX2.js.gz differ diff --git a/web-app/build/assets/Tools-Cdske3tf.js.gz b/web-app/build/assets/Tools-Cdske3tf.js.gz new file mode 100644 index 0000000000..e570238dbd Binary files /dev/null and b/web-app/build/assets/Tools-Cdske3tf.js.gz differ diff --git a/web-app/build/assets/Tools-Da7B-gQ7.js.gz b/web-app/build/assets/Tools-Da7B-gQ7.js.gz deleted file mode 100644 index c445ec994a..0000000000 Binary files a/web-app/build/assets/Tools-Da7B-gQ7.js.gz and /dev/null differ diff --git a/web-app/build/assets/Trace-D93-ruG8.js.gz b/web-app/build/assets/Trace-D93-ruG8.js.gz new file mode 100644 index 0000000000..9943ecd888 Binary files /dev/null and b/web-app/build/assets/Trace-D93-ruG8.js.gz differ diff --git a/web-app/build/assets/Trace-DALhpSna.js.gz b/web-app/build/assets/Trace-DALhpSna.js.gz deleted file mode 100644 index ce436ed6fd..0000000000 Binary files a/web-app/build/assets/Trace-DALhpSna.js.gz and /dev/null differ diff --git a/web-app/build/assets/UpdateTierCredentialsModal-D8GDNapf.js.gz b/web-app/build/assets/UpdateTierCredentialsModal-D8GDNapf.js.gz new file mode 100644 index 0000000000..31cf2402ef Binary files /dev/null and b/web-app/build/assets/UpdateTierCredentialsModal-D8GDNapf.js.gz differ diff --git a/web-app/build/assets/UpdateTierCredentialsModal-Dliav8ua.js.gz b/web-app/build/assets/UpdateTierCredentialsModal-Dliav8ua.js.gz deleted file mode 100644 index ec0d0d9891..0000000000 Binary files a/web-app/build/assets/UpdateTierCredentialsModal-Dliav8ua.js.gz and /dev/null differ diff --git a/web-app/build/assets/Users-1HBCqyMK.js.gz b/web-app/build/assets/Users-1HBCqyMK.js.gz new file mode 100644 index 0000000000..6bf2fea7ec Binary files /dev/null and b/web-app/build/assets/Users-1HBCqyMK.js.gz differ diff --git a/web-app/build/assets/Users-Dpf6ODRB.js.gz b/web-app/build/assets/Users-Dpf6ODRB.js.gz deleted file mode 100644 index ae4ec19b00..0000000000 Binary files a/web-app/build/assets/Users-Dpf6ODRB.js.gz and /dev/null differ diff --git a/web-app/build/assets/UsersSelectors-CwjpU9__.js.gz b/web-app/build/assets/UsersSelectors-CwjpU9__.js.gz new file mode 100644 index 0000000000..542a08e0e7 Binary files /dev/null and b/web-app/build/assets/UsersSelectors-CwjpU9__.js.gz differ diff --git a/web-app/build/assets/UsersSelectors-DGAPoZkL.js.gz b/web-app/build/assets/UsersSelectors-DGAPoZkL.js.gz deleted file mode 100644 index f064af835e..0000000000 Binary files a/web-app/build/assets/UsersSelectors-DGAPoZkL.js.gz and /dev/null differ diff --git a/web-app/build/assets/Watch-B7fM1DUX.js.gz b/web-app/build/assets/Watch-B7fM1DUX.js.gz new file mode 100644 index 0000000000..c1a5144041 Binary files /dev/null and b/web-app/build/assets/Watch-B7fM1DUX.js.gz differ diff --git a/web-app/build/assets/Watch-D80AA84z.js.gz b/web-app/build/assets/Watch-D80AA84z.js.gz deleted file mode 100644 index f5238ba9f8..0000000000 Binary files a/web-app/build/assets/Watch-D80AA84z.js.gz and /dev/null differ diff --git a/web-app/build/assets/YAxis-B9K089Ug.js.gz b/web-app/build/assets/YAxis-B9K089Ug.js.gz deleted file mode 100644 index 249c78254e..0000000000 Binary files a/web-app/build/assets/YAxis-B9K089Ug.js.gz and /dev/null differ diff --git a/web-app/build/assets/YAxis-CB2hwSGc.js.gz b/web-app/build/assets/YAxis-CB2hwSGc.js.gz new file mode 100644 index 0000000000..4d20c57023 Binary files /dev/null and b/web-app/build/assets/YAxis-CB2hwSGc.js.gz differ diff --git a/web-app/build/assets/es-BbPD0nNI.js.gz b/web-app/build/assets/es-BbPD0nNI.js.gz deleted file mode 100644 index c20062fba8..0000000000 Binary files a/web-app/build/assets/es-BbPD0nNI.js.gz and /dev/null differ diff --git a/web-app/build/assets/generateCategoricalChart-BnVaLGo3.js.gz b/web-app/build/assets/generateCategoricalChart-BnVaLGo3.js.gz deleted file mode 100644 index 4ff7973d8c..0000000000 Binary files a/web-app/build/assets/generateCategoricalChart-BnVaLGo3.js.gz and /dev/null differ diff --git a/web-app/build/assets/generateCategoricalChart-odE_ntaK.js.gz b/web-app/build/assets/generateCategoricalChart-odE_ntaK.js.gz new file mode 100644 index 0000000000..3d056ddedc Binary files /dev/null and b/web-app/build/assets/generateCategoricalChart-odE_ntaK.js.gz differ diff --git a/web-app/build/assets/get-D-5ICXMN.js.gz b/web-app/build/assets/get-D-5ICXMN.js.gz deleted file mode 100644 index 6a9efd81e7..0000000000 Binary files a/web-app/build/assets/get-D-5ICXMN.js.gz and /dev/null differ diff --git a/web-app/build/assets/get-i4FgFrza.js.gz b/web-app/build/assets/get-i4FgFrza.js.gz new file mode 100644 index 0000000000..083e6eab2d Binary files /dev/null and b/web-app/build/assets/get-i4FgFrza.js.gz differ diff --git a/web-app/build/assets/index-BQJWaZ8K.css.gz b/web-app/build/assets/index-BQJWaZ8K.css.gz deleted file mode 100644 index 97e608b9ca..0000000000 Binary files a/web-app/build/assets/index-BQJWaZ8K.css.gz and /dev/null differ diff --git a/web-app/build/assets/index-BcBT2m8l.js.gz b/web-app/build/assets/index-BcBT2m8l.js.gz new file mode 100644 index 0000000000..b51d85dcc6 Binary files /dev/null and b/web-app/build/assets/index-BcBT2m8l.js.gz differ diff --git a/web-app/build/assets/index-BvVSYA6O.js.gz b/web-app/build/assets/index-BvVSYA6O.js.gz deleted file mode 100644 index 52a3db64a9..0000000000 Binary files a/web-app/build/assets/index-BvVSYA6O.js.gz and /dev/null differ diff --git a/web-app/build/assets/index-clIzMmhk.css.gz b/web-app/build/assets/index-clIzMmhk.css.gz new file mode 100644 index 0000000000..363669cfc3 Binary files /dev/null and b/web-app/build/assets/index-clIzMmhk.css.gz differ diff --git a/web-app/build/assets/inspectDownload-BFXjXcQY.js.gz b/web-app/build/assets/inspectDownload-BFXjXcQY.js.gz deleted file mode 100644 index c66ceb43de..0000000000 Binary files a/web-app/build/assets/inspectDownload-BFXjXcQY.js.gz and /dev/null differ diff --git a/web-app/build/assets/inspectDownload-D_wldcvn.js.gz b/web-app/build/assets/inspectDownload-D_wldcvn.js.gz new file mode 100644 index 0000000000..77e761b161 Binary files /dev/null and b/web-app/build/assets/inspectDownload-D_wldcvn.js.gz differ diff --git a/web-app/build/assets/jsx-runtime-OPrhpiUg.js.gz b/web-app/build/assets/jsx-runtime-D0rXHccJ.js.gz similarity index 99% rename from web-app/build/assets/jsx-runtime-OPrhpiUg.js.gz rename to web-app/build/assets/jsx-runtime-D0rXHccJ.js.gz index c6e7cabfcb..bede14c65e 100644 Binary files a/web-app/build/assets/jsx-runtime-OPrhpiUg.js.gz and b/web-app/build/assets/jsx-runtime-D0rXHccJ.js.gz differ diff --git a/web-app/build/assets/lang-Aa4XqCxi.js.gz b/web-app/build/assets/lang-Aa4XqCxi.js.gz new file mode 100644 index 0000000000..1828e71b97 Binary files /dev/null and b/web-app/build/assets/lang-Aa4XqCxi.js.gz differ diff --git a/web-app/build/assets/lang-DBDeDJwU.js.gz b/web-app/build/assets/lang-DBDeDJwU.js.gz deleted file mode 100644 index 2f9beed90b..0000000000 Binary files a/web-app/build/assets/lang-DBDeDJwU.js.gz and /dev/null differ diff --git a/web-app/build/assets/lib-BThoYwzc.js.gz b/web-app/build/assets/lib-BThoYwzc.js.gz new file mode 100644 index 0000000000..2631b5c1f0 Binary files /dev/null and b/web-app/build/assets/lib-BThoYwzc.js.gz differ diff --git a/web-app/build/assets/lib-D1dHAysj.js.gz b/web-app/build/assets/lib-D1dHAysj.js.gz deleted file mode 100644 index 9057c1c84c..0000000000 Binary files a/web-app/build/assets/lib-D1dHAysj.js.gz and /dev/null differ diff --git a/web-app/build/assets/preload-helper-kNaey6uv.js.gz b/web-app/build/assets/preload-helper-kNaey6uv.js.gz new file mode 100644 index 0000000000..cbd59ffa9b Binary files /dev/null and b/web-app/build/assets/preload-helper-kNaey6uv.js.gz differ diff --git a/web-app/build/assets/store-BgHIlGyA.js.gz b/web-app/build/assets/store-BgHIlGyA.js.gz deleted file mode 100644 index c45719b367..0000000000 Binary files a/web-app/build/assets/store-BgHIlGyA.js.gz and /dev/null differ diff --git a/web-app/build/assets/store-DtJUL4g9.js.gz b/web-app/build/assets/store-DtJUL4g9.js.gz new file mode 100644 index 0000000000..bed1a99d38 Binary files /dev/null and b/web-app/build/assets/store-DtJUL4g9.js.gz differ diff --git a/web-app/build/assets/styleLibrary-B5V3Qgq3.js.gz b/web-app/build/assets/styleLibrary-B5V3Qgq3.js.gz deleted file mode 100644 index 4fee28fa72..0000000000 Binary files a/web-app/build/assets/styleLibrary-B5V3Qgq3.js.gz and /dev/null differ diff --git a/web-app/build/assets/styleLibrary-C4m8p8Qx.js.gz b/web-app/build/assets/styleLibrary-C4m8p8Qx.js.gz new file mode 100644 index 0000000000..4c20a6afd0 Binary files /dev/null and b/web-app/build/assets/styleLibrary-C4m8p8Qx.js.gz differ diff --git a/web-app/build/assets/useDiagnosticSocket-C3YcbDUw.js.gz b/web-app/build/assets/useDiagnosticSocket-C3YcbDUw.js.gz new file mode 100644 index 0000000000..d1440a7e6e Binary files /dev/null and b/web-app/build/assets/useDiagnosticSocket-C3YcbDUw.js.gz differ diff --git a/web-app/build/assets/useDiagnosticSocket-M44R6tK6.js.gz b/web-app/build/assets/useDiagnosticSocket-M44R6tK6.js.gz deleted file mode 100644 index 3f6cfd674f..0000000000 Binary files a/web-app/build/assets/useDiagnosticSocket-M44R6tK6.js.gz and /dev/null differ diff --git a/web-app/build/assets/utils-BP8kQP8H.js.gz b/web-app/build/assets/utils-BP8kQP8H.js.gz deleted file mode 100644 index d6386ab1ce..0000000000 Binary files a/web-app/build/assets/utils-BP8kQP8H.js.gz and /dev/null differ diff --git a/web-app/build/assets/utils-BRciijWb.js.gz b/web-app/build/assets/utils-BRciijWb.js.gz deleted file mode 100644 index 5d9c5d3cee..0000000000 Binary files a/web-app/build/assets/utils-BRciijWb.js.gz and /dev/null differ diff --git a/web-app/build/assets/utils-DGxIBQ0y.js.gz b/web-app/build/assets/utils-DGxIBQ0y.js.gz new file mode 100644 index 0000000000..67dea8607d Binary files /dev/null and b/web-app/build/assets/utils-DGxIBQ0y.js.gz differ diff --git a/web-app/build/assets/utils-KP8nvXDv.js.gz b/web-app/build/assets/utils-KP8nvXDv.js.gz new file mode 100644 index 0000000000..7d7dcae60b Binary files /dev/null and b/web-app/build/assets/utils-KP8nvXDv.js.gz differ diff --git a/web-app/build/assets/withSuspense-D7Tme-q8.js.gz b/web-app/build/assets/withSuspense-D7Tme-q8.js.gz deleted file mode 100644 index 846ca71c5d..0000000000 Binary files a/web-app/build/assets/withSuspense-D7Tme-q8.js.gz and /dev/null differ diff --git a/web-app/build/assets/withSuspense-DTnE75Gm.js.gz b/web-app/build/assets/withSuspense-DTnE75Gm.js.gz new file mode 100644 index 0000000000..ef26d6fe44 Binary files /dev/null and b/web-app/build/assets/withSuspense-DTnE75Gm.js.gz differ diff --git a/web-app/build/index.html b/web-app/build/index.html index 2aeb8eb3f9..7229592d10 100644 --- a/web-app/build/index.html +++ b/web-app/build/index.html @@ -29,13 +29,13 @@ SILO Console - - - - - - - + + + + + + + diff --git a/web-app/e2e/consts.ts b/web-app/e2e/consts.ts index 2db0b4a56c..056bee5378 100644 --- a/web-app/e2e/consts.ts +++ b/web-app/e2e/consts.ts @@ -16,7 +16,8 @@ export const minioadminFile = "playwright/.auth/admin.json"; -export const SERVER_ENDPOINT = "http://localhost:9090"; +export const SERVER_ENDPOINT = + process.env.CONSOLE_TEST_ENDPOINT || "http://localhost:9090"; export const BUCKET_LIST_PAGE = `${SERVER_ENDPOINT}/buckets`; export const adminAccessKey = "minioadmin"; diff --git a/web-app/e2e/download-progress.spec.ts b/web-app/e2e/download-progress.spec.ts index a2fc5c95af..f129996fd4 100644 --- a/web-app/e2e/download-progress.spec.ts +++ b/web-app/e2e/download-progress.spec.ts @@ -26,7 +26,7 @@ const objectNames = [folderObject, folderZeroObject, knownObject, zeroObject]; const minioClient = new Minio.Client({ endPoint: "localhost", - port: 9000, + port: Number(process.env.SILO_TEST_PORT || 9000), useSSL: false, accessKey: "minioadmin", secretKey: "minioadmin", diff --git a/web-app/e2e/fixtures/localization-harness.html b/web-app/e2e/fixtures/localization-harness.html new file mode 100644 index 0000000000..78fe6f4104 --- /dev/null +++ b/web-app/e2e/fixtures/localization-harness.html @@ -0,0 +1,11 @@ + + + + + Localization regression harness + + +
+ + + diff --git a/web-app/e2e/fixtures/localizationHarness.tsx b/web-app/e2e/fixtures/localizationHarness.tsx new file mode 100644 index 0000000000..fd8a05323a --- /dev/null +++ b/web-app/e2e/fixtures/localizationHarness.tsx @@ -0,0 +1,67 @@ +import React from "react"; +import { createRoot } from "react-dom/client"; +import { Provider } from "react-redux"; +import { MemoryRouter } from "react-router-dom"; +import { store } from "../../src/store"; +import { setLanguage } from "../../src/systemSlice"; +import { translate } from "../../src/i18n/lang"; +import NotFound from "../../src/screens/NotFoundPage"; +import CommonCard from "../../src/screens/Console/Dashboard/CommonCard"; +import { messageForError } from "../../src/screens/Console/Logs/ErrorLogs/LogLine"; +import HealthInfoResults from "../../src/screens/Console/HealthInfo/HealthInfoResults"; +const language = + new URLSearchParams(location.search).get("lang") === "zh" ? "zh" : "en"; +store.dispatch(setLanguage(language)); +const log = { + time: "12:00:00 UTC 01/01/2026", + api: { name: "GetObject" }, + deploymentid: "deployment-test", + requestID: "request-test", + remotehost: "127.0.0.1", + userAgent: "test-agent", + error: { message: "raw error payload", source: ["raw stack payload"] }, +} as any; +const info = { + sys: { + cpus: [], + partitions: [], + osinfo: [], + meminfo: [], + procinfo: [], + netinfo: [], + errors: [], + services: [], + config: {}, + }, + minio: { + config: { config: {} }, + info: { + mode: "distributed", + deploymentID: "deployment-test", + buckets: { count: 1 }, + objects: { count: 2 }, + usage: { size: 3 }, + backend: {}, + servers: [], + metrics: {}, + }, + }, +} as any; +createRoot(document.getElementById("root")!).render( + + +
+ +
+
+ +
+
+ {messageForError(log, (text) => translate(language, text))} +
+
+ +
+
+
, +); diff --git a/web-app/e2e/localization-render.unit.ts b/web-app/e2e/localization-render.unit.ts new file mode 100644 index 0000000000..54e5765cc5 --- /dev/null +++ b/web-app/e2e/localization-render.unit.ts @@ -0,0 +1,63 @@ +// Copyright (c) 2026 PGSTY +// SPDX-License-Identifier: AGPL-3.0-or-later +import { test, expect, chromium, Browser } from "@playwright/test"; +import { spawn, ChildProcess } from "node:child_process"; +import { once } from "node:events"; +let server: ChildProcess, browser: Browser, base: string; +test.beforeAll(async () => { + // Vite mutates process-level build state. Keep the dev fixture in a separate + // process so later production-bundle tests see their own clean environment. + server = spawn( + process.execPath, + [ + "--input-type=module", + "-e", + ` + import { createServer } from 'vite'; + const server = await createServer({ logLevel: 'silent', server: { host: '127.0.0.1', port: 0, open: false } }); + await server.listen(); + process.send('http://127.0.0.1:' + server.httpServer.address().port); + `, + ], + { stdio: ["ignore", "ignore", "inherit", "ipc"] }, + ); + base = await new Promise((resolve, reject) => { + server.once("message", (message) => resolve(String(message))); + server.once("error", reject); + server.once("exit", (code) => + reject(new Error(`Fixture server exited: ${code}`)), + ); + }); + browser = await chromium.launch(); +}); +test.afterAll(async () => { + await browser?.close(); + if (server && server.exitCode === null) { + const stopped = once(server, "exit"); + server.kill(); + await stopped; + } +}); +for (const lang of ["en", "zh"]) { + test(`remaining screen labels render in ${lang} while payloads stay literal`, async () => { + const page = await browser.newPage(); + await page.goto( + `${base}/e2e/fixtures/localization-harness.html?lang=${lang}`, + ); + await expect(page.getByTestId("not-found")).toContainText( + lang === "zh" ? "找不到此页面" : "page could not be found", + ); + await expect(page.getByTestId("card")).toContainText( + lang === "zh" ? "查看全部" : "View All", + ); + await expect(page.getByTestId("log")).toContainText( + lang === "zh" ? "远程主机:" : "Remote host:", + ); + await expect(page.getByTestId("log")).toContainText("raw error payload"); + await expect(page.getByTestId("log")).toContainText("GetObject"); + await expect(page.getByTestId("health")).toContainText( + lang === "zh" ? "部署 ID:" : "Deployment ID:", + ); + await page.close(); + }); +} diff --git a/web-app/e2e/mds-select.unit.ts b/web-app/e2e/mds-select.unit.ts index 31d6b77940..c35fe6f672 100644 --- a/web-app/e2e/mds-select.unit.ts +++ b/web-app/e2e/mds-select.unit.ts @@ -12,6 +12,10 @@ let browser: Browser; let script: string; test.beforeAll(async () => { + // Other fixture servers leave NODE_ENV=development in this worker. JSX + // transformation and React's runtime must both use production for this bundle. + const previousNodeEnv = process.env.NODE_ENV; + process.env.NODE_ENV = "production"; // Bundle the installed MDS distribution, as Console does. The regression is // an event-ordering bug; checking source text would miss actual selection. const result = await build({ @@ -29,6 +33,8 @@ test.beforeAll(async () => { }, }, }); + if (previousNodeEnv === undefined) delete process.env.NODE_ENV; + else process.env.NODE_ENV = previousNodeEnv; const output = Array.isArray(result) ? result[0] : result; if (!("output" in output)) throw new Error("MDS harness build has no output"); const chunk = output.output.find((item) => item.type === "chunk"); diff --git a/web-app/e2e/multi-download.spec.ts b/web-app/e2e/multi-download.spec.ts new file mode 100644 index 0000000000..9dc9c9cf6e --- /dev/null +++ b/web-app/e2e/multi-download.spec.ts @@ -0,0 +1,289 @@ +// Copyright (c) 2026 PGSTY +// SPDX-License-Identifier: AGPL-3.0-or-later +import { test, expect, Page } from "@playwright/test"; +import { randomUUID, randomBytes } from "node:crypto"; +import { readFile } from "node:fs/promises"; +import { unzipSync } from "fflate"; +import * as Minio from "minio"; +import { minioadminFile, SERVER_ENDPOINT } from "./consts"; + +test.describe.configure({ mode: "serial" }); +test.use({ storageState: minioadminFile }); +const bucket = `multi-zip-${randomUUID()}`; +const client = new Minio.Client({ + endPoint: "localhost", + port: Number(process.env.SILO_TEST_PORT || 9000), + useSSL: false, + accessKey: "minioadmin", + secretKey: "minioadmin", +}); +const files = { + "data.bin": randomBytes(256 * 1024), + "zero.txt": Buffer.alloc(0), + "nested/中文.txt": Buffer.from("nested content"), +}; +const sizeAdvice = + "For selections above 5 GiB or of unknown size, MCLI is recommended. This ZIP will stream without buffering in memory."; +test.beforeAll(async () => { + await client.makeBucket(bucket); + for (const [key, body] of Object.entries(files)) + await client.putObject(bucket, key, body); +}); +test.afterAll(async () => { + await client.removeObjects(bucket, Object.keys(files)); + await client.removeBucket(bucket); +}); +async function select(page: Page, names: string[]) { + await page.goto(`${SERVER_ENDPOINT}/browser/${bucket}`); + for (const name of names) { + const checkbox = page.locator(`input[type="checkbox"][value="${name}"]`); + await checkbox.waitFor({ state: "attached" }); + await page.locator("label").filter({ has: checkbox }).click(); + } +} +async function picker(page: Page, delay = 0) { + await page.addInitScript((delay) => { + const state = { + chunks: [] as number[][], + closed: false, + aborted: false, + writes: 0, + releaseWrite: undefined as (() => void) | undefined, + }; + (window as any).__zipState = state; + (window as any).showSaveFilePicker = async () => ({ + createWritable: async () => + new WritableStream({ + async write(chunk: Uint8Array) { + state.writes++; + if (delay === -1 && state.writes === 1) { + await new Promise((resolve) => { + state.releaseWrite = resolve; + }); + } else if (delay > 0) { + await new Promise((resolve) => setTimeout(resolve, delay)); + } + state.chunks.push([...chunk]); + }, + close() { + state.closed = true; + }, + abort() { + state.aborted = true; + }, + }), + }); + }, delay); +} +async function openManager(page: Page) { + await page.locator("#object-manager-toggle").click(); +} + +test("native multi-selection and recursive prefixes produce a real ZIP", async ({ + page, +}) => { + await page.addInitScript(() => { + (window as any).showSaveFilePicker = undefined; + }); + await select(page, ["data.bin", "nested/"]); + const downloaded = page.waitForEvent("download"); + await page.getByRole("button", { name: "Download", exact: true }).click(); + const download = await downloaded; + expect(download.suggestedFilename()).toMatch(/\.zip$/); + const zipped = unzipSync( + new Uint8Array(await readFile((await download.path())!)), + ); + expect(Buffer.from(zipped["data.bin"])).toEqual(files["data.bin"]); + expect(new TextDecoder().decode(zipped["nested/中文.txt"])).toBe( + "nested content", + ); + // A recursive prefix has an unknown total; native handoff must not replace + // its advisory with the normal browser-manager toast. + await expect(page.getByText(sizeAdvice, { exact: true })).toBeVisible(); + await openManager(page); + await expect( + page + .getByText( + "Track or cancel this download in your browser's download manager.", + { exact: true }, + ) + .last(), + ).toBeVisible(); + await download.delete(); +}); + +test("large selection keeps its MCLI advisory while streaming", async ({ + page, +}) => { + await picker(page); + await page.routeWebSocket("**/ws/objectManager", (socket) => { + const server = socket.connectToServer(); + server.onMessage((message) => { + const json = JSON.parse(message.toString()); + // Test the size decision without uploading gigabytes of fixture data. + for (const object of json.data || []) object.size = 6 * 1024 ** 3; + socket.send(JSON.stringify(json)); + }); + }); + await select(page, ["data.bin", "zero.txt"]); + await page.getByRole("button", { name: "Download", exact: true }).click(); + await expect(page.getByText(sizeAdvice, { exact: true })).toBeVisible(); + await expect + .poll(() => page.evaluate(() => (window as any).__zipState.closed)) + .toBe(true); +}); + +test("file writer streams multiple files and blocks duplicate clicks", async ({ + page, +}) => { + await picker(page, 100); + let requests = 0; + page.on("request", (request) => { + if (request.url().includes("/download-multiple")) requests++; + }); + await select(page, ["data.bin", "zero.txt"]); + await page.getByRole("button", { name: "Download", exact: true }).dblclick(); + await expect + .poll(() => page.evaluate(() => (window as any).__zipState.closed)) + .toBe(true); + expect(requests).toBe(1); + const chunks = await page.evaluate( + () => (window as any).__zipState.chunks as number[][], + ); + const zipped = unzipSync(new Uint8Array(chunks.flat())); + expect(Buffer.from(zipped["data.bin"])).toEqual(files["data.bin"]); + expect(zipped["zero.txt"]).toHaveLength(0); +}); + +test("cancel aborts a running ZIP file writer", async ({ page }) => { + await picker(page, -1); + await select(page, ["data.bin", "nested/"]); + await page.getByRole("button", { name: "Download", exact: true }).click(); + await expect + .poll(() => page.evaluate(() => (window as any).__zipState.writes)) + .toBeGreaterThan(0); + await openManager(page); + await page + .getByRole("button", { name: "Cancel transfer", exact: true }) + .click(); + await page.evaluate(() => (window as any).__zipState.releaseWrite()); + await expect + .poll(() => page.evaluate(() => (window as any).__zipState.aborted)) + .toBe(true); + expect(await page.evaluate(() => (window as any).__zipState.closed)).toBe( + false, + ); +}); + +test("cancelling a queued save dialog settles without waiting for a download slot", async ({ + page, +}) => { + await page.route("**/api/v1/session", async (route) => { + const response = await route.fetch(); + const json = await response.json(); + json.envConstants = { ...json.envConstants, maxConcurrentDownloads: 1 }; + await route.fulfill({ response, json }); + }); + await page.addInitScript(() => { + let calls = 0; + (window as any).showSaveFilePicker = () => { + if (++calls === 1) return new Promise(() => {}); + return Promise.reject(new DOMException("Cancelled", "AbortError")); + }; + }); + await select(page, ["data.bin", "zero.txt"]); + await page.getByRole("button", { name: "Download", exact: true }).click(); + for (const name of ["zero.txt", "nested/"]) { + const checkbox = page.locator(`input[type="checkbox"][value="${name}"]`); + await page.locator("label").filter({ has: checkbox }).click(); + } + await page.getByRole("button", { name: "Download", exact: true }).click(); + await openManager(page); + await expect( + page.getByRole("button", { name: "Cancel transfer", exact: true }), + ).toHaveCount(1); + await expect( + page.getByRole("button", { name: "Remove transfer", exact: true }), + ).toHaveCount(1); +}); + +test("server failure aborts the selected file without a successful download", async ({ + page, +}) => { + await picker(page); + await page.route("**/objects/download-multiple", (route) => + route.fulfill({ status: 403, json: { message: "Access denied" } }), + ); + await select(page, ["data.bin", "zero.txt"]); + await page.getByRole("button", { name: "Download", exact: true }).click(); + await expect + .poll(() => page.evaluate(() => (window as any).__zipState.aborted)) + .toBe(true); + expect(await page.evaluate(() => (window as any).__zipState.closed)).toBe( + false, + ); + await openManager(page); + await expect( + page.getByText("Error: Unexpected response, download incomplete.", { + exact: true, + }), + ).toBeVisible(); +}); + +for (const blocked of [false, true]) { + test(`native ZIP reports an error when the response ${blocked ? "cannot" : "can"} be framed`, async ({ + page, + }) => { + await page.addInitScript(() => { + (window as any).showSaveFilePicker = undefined; + }); + await select(page, ["data.bin", "zero.txt"]); + await page.route("**/objects/download-multiple", (route) => + blocked + ? route.fulfill({ + status: 403, + headers: { "X-Frame-Options": "DENY" }, + body: "forbidden", + }) + : route.continue({ postData: "objects=%5B%5D" }), + ); + await page.getByRole("button", { name: "Download", exact: true }).click(); + await openManager(page); + await expect( + page.getByText( + blocked + ? "Error: Unexpected response, download incomplete." + : "Error: invalid download selection", + { exact: true }, + ), + ).toBeVisible(); + await expect( + page.getByText( + "Track or cancel this download in your browser's download manager.", + { exact: true }, + ), + ).toHaveCount(0); + }); +} + +test("native ZIP checks an expired session before handing off to the browser", async ({ + page, +}) => { + await page.addInitScript(() => { + (window as any).showSaveFilePicker = undefined; + }); + await select(page, ["data.bin", "zero.txt"]); + await page.route("**/api/v1/session", (route) => + route.fulfill({ status: 401, json: { message: "invalid session" } }), + ); + let downloads = 0; + let requests = 0; + page.on("download", () => downloads++); + page.on("request", (request) => { + if (request.url().endsWith("/objects/download-multiple")) requests++; + }); + await page.getByRole("button", { name: "Download", exact: true }).click(); + await expect(page).toHaveURL(/\/login$/); + expect(downloads).toBe(0); + expect(requests).toBe(0); +}); diff --git a/web-app/e2e/object-detail-stale.spec.ts b/web-app/e2e/object-detail-stale.spec.ts index 7052373288..2a1b50ad88 100644 --- a/web-app/e2e/object-detail-stale.spec.ts +++ b/web-app/e2e/object-detail-stale.spec.ts @@ -29,7 +29,7 @@ const deleteCurrentObject = "epsilon.txt"; const minioClient = new Minio.Client({ endPoint: "localhost", - port: 9000, + port: Number(process.env.SILO_TEST_PORT || 9000), useSSL: false, accessKey: "minioadmin", secretKey: "minioadmin", diff --git a/web-app/e2e/ui-recovery.spec.ts b/web-app/e2e/ui-recovery.spec.ts new file mode 100644 index 0000000000..6296ffd6e9 --- /dev/null +++ b/web-app/e2e/ui-recovery.spec.ts @@ -0,0 +1,134 @@ +// Copyright (c) 2026 PGSTY +// SPDX-License-Identifier: AGPL-3.0-or-later +import { expect, test } from "@playwright/test"; +import AxeBuilder from "@axe-core/playwright"; +import { minioadminFile, SERVER_ENDPOINT } from "./consts"; + +test.use({ storageState: minioadminFile }); +for (const lang of ["en", "zh"]) { + test.describe(lang, () => { + test.beforeEach(async ({ page }) => { + await page.addInitScript((language) => { + localStorage.setItem("language", language); + localStorage.setItem("sidebarOpen", "{broken"); + localStorage.setItem("keep-this-preference", "kept"); + }, lang); + }); + test("malformed deep links recover without clearing preferences", async ({ + page, + }) => { + // Set the address before the SPA boots. Invalid percent escapes cannot + // be sent as HTTP document URLs because servers reject them first. + await page.addInitScript(() => { + const target = new URLSearchParams(location.search).get("test-route"); + if (target) history.replaceState({}, "", target); + }); + for (const suffix of ["%", "%FF", "%E0%A4%A"]) { + await page.goto( + `${SERVER_ENDPOINT}/?test-route=${encodeURIComponent(`/browser/bucket/${suffix}`)}`, + ); + await expect( + page.getByText(lang === "zh" ? "404 错误" : "404 Error", { + exact: true, + }), + ).toBeVisible(); + await page + .getByRole("link", { + name: lang === "zh" ? "返回首页" : "Return home", + }) + .click(); + await expect(page.locator("#sign-out")).toBeVisible(); + expect( + await page.evaluate(() => + localStorage.getItem("keep-this-preference"), + ), + ).toBe("kept"); + } + }); + for (const width of [1440, 390]) { + test(`navigation names and keyboard tooltip at width ${width}`, async ({ + page, + }) => { + await page.setViewportSize({ width, height: 900 }); + await page.goto(`${SERVER_ENDPOINT}/buckets`); + const signOut = page.locator("#sign-out"); + await expect(signOut).toHaveAccessibleName( + lang === "zh" ? "登出" : "Sign Out", + ); + const auditNames = async () => { + const result = await new AxeBuilder({ page }) + .withRules(["button-name", "link-name", "aria-command-name"]) + .analyze(); + expect(result.violations).toEqual([]); + }; + await auditNames(); + const toggle = page.getByRole("button", { + name: + width < 600 + ? lang === "zh" + ? "展开菜单" + : "Expand menu" + : lang === "zh" + ? "折叠菜单" + : "Collapse menu", + exact: true, + }); + await toggle.focus(); + await page.keyboard.press("Enter"); + await expect(signOut).toHaveAccessibleName( + lang === "zh" ? "登出" : "Sign Out", + ); + await auditNames(); + const refresh = page.locator("#refresh-buckets"); + await expect(refresh).toHaveAccessibleName( + lang === "zh" ? "刷新存储桶" : "Refresh buckets", + ); + await refresh.focus(); + await expect(page.getByRole("tooltip")).toBeVisible(); + await expect(refresh).toHaveAccessibleDescription( + lang === "zh" ? "刷新" : "Refresh", + ); + await page.keyboard.press("Escape"); + await expect(page.getByRole("tooltip")).toHaveCount(0); + }); + } + test("sign-out stays localized across a responsive relayout", async ({ + page, + }) => { + await page.setViewportSize({ width: 1440, height: 900 }); + await page.goto(`${SERVER_ENDPOINT}/buckets`); + for (const width of [390, 1440]) { + await page.setViewportSize({ width, height: 900 }); + await expect(page.locator("#sign-out")).toHaveAccessibleName( + lang === "zh" ? "登出" : "Sign Out", + ); + } + }); + test("root render failure has a localized recovery action", async ({ + page, + }) => { + await page.route("**/api/v1/buckets", (route) => + route.fulfill({ + json: { + buckets: [ + { name: { malformed: true }, creation_date: "2026-01-01" }, + ], + }, + }), + ); + await page.goto(`${SERVER_ENDPOINT}/browser`); + await expect(page.getByRole("alert")).toContainText( + lang === "zh" ? "无法显示此页面。" : "Unable to display this page.", + ); + await expect( + page.getByRole("button", { + name: lang === "zh" ? "重新加载页面" : "Reload page", + exact: true, + }), + ).toBeVisible(); + expect( + await page.evaluate(() => localStorage.getItem("keep-this-preference")), + ).toBe("kept"); + }); + }); +} diff --git a/web-app/e2e/ui-recovery.unit.ts b/web-app/e2e/ui-recovery.unit.ts new file mode 100644 index 0000000000..7598758ecc --- /dev/null +++ b/web-app/e2e/ui-recovery.unit.ts @@ -0,0 +1,63 @@ +// Copyright (c) 2026 PGSTY +// SPDX-License-Identifier: AGPL-3.0-or-later +import { expect, test } from "@playwright/test"; +import { isValidPathname } from "../src/utils/routePath"; +import { getStoredSidebarOpen } from "../src/utils/sidebarState"; +import { uiSourceViolations } from "../hack/ui-source-guard.mjs"; +import { mkdtempSync, writeFileSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; + +for (const raw of [ + "{", + "null", + "false", + "[]", + '"open"', + '{"open":"false"}', + '{"open":0}', +]) { + test(`invalid sidebar preference ${raw} falls back safely`, () => { + expect(getStoredSidebarOpen(() => raw)).toBe(true); + }); +} +test("valid sidebar preference survives and inaccessible storage falls back", () => { + expect(getStoredSidebarOpen(() => '{"open":false}')).toBe(false); + expect( + getStoredSidebarOpen(() => { + throw new Error("blocked"); + }), + ).toBe(true); +}); +for (const value of [ + "/browser/b/%", + "/browser/b/%FF", + "/console/subpath/browser/b/%E0%A4%A", +]) { + test(`reject malformed route ${value}`, () => + expect(isValidPathname(value)).toBe(false)); +} +for (const value of [ + "/browser/b/中文", + "/browser/b/%E4%B8%AD%E6%96%87", + "/browser/b/%252F", + "/console/subpath/browser/b/a%2Fb%25c", +]) { + test(`accept encoded object route ${value}`, () => + expect(isValidPathname(value)).toBe(true)); +} +test("UI literals and icon controls respect localization and accessible names", () => { + expect(uiSourceViolations()).toEqual([]); +}); +test("literal accessible labels fail the guard while localized labels and ID references pass", () => { + const dir = mkdtempSync(join(tmpdir(), "console-ui-labels-")); + try { + writeFileSync( + join(dir, "Example.tsx"), + '<>{" "} + {t("Return home")} + + ); + } +} diff --git a/web-app/src/common/Tooltip.tsx b/web-app/src/common/Tooltip.tsx new file mode 100644 index 0000000000..17d5900e25 --- /dev/null +++ b/web-app/src/common/Tooltip.tsx @@ -0,0 +1,101 @@ +// Copyright (c) 2026 PGSTY +// SPDX-License-Identifier: AGPL-3.0-or-later + +import React, { cloneElement, useEffect, useId, useRef, useState } from "react"; +import { createPortal } from "react-dom"; +import type { Tooltip as MDSTooltip } from "mds"; + +// Preserve the MDS call-site API while providing keyboard focus, a stable +// accessible description while open, Escape dismissal and a hoverable tooltip. +export const Tooltip = ({ + children, + tooltip, + errorProps, + placement = "bottom", +}: React.ComponentProps) => { + const id = useId(); + const anchor = useRef(null); + const timer = useRef | undefined>(undefined); + const [bounds, setBounds] = useState(null); + const cancelHide = () => clearTimeout(timer.current); + const show = () => { + cancelHide(); + setBounds(anchor.current?.getBoundingClientRect() || null); + }; + const hide = () => { + cancelHide(); + timer.current = setTimeout(() => { + if (!anchor.current?.contains(document.activeElement)) setBounds(null); + }, 150); + }; + useEffect(() => () => clearTimeout(timer.current), []); + useEffect(() => { + if (!bounds) return; + const dismiss = () => setBounds(null); + const onMove = () => { + if (anchor.current?.contains(document.activeElement)) { + setBounds(anchor.current.getBoundingClientRect()); + } else dismiss(); + }; + const onKey = (event: KeyboardEvent) => { + if (event.key === "Escape") dismiss(); + }; + window.addEventListener("keydown", onKey); + window.addEventListener("scroll", onMove, true); + window.addEventListener("resize", onMove); + return () => { + window.removeEventListener("keydown", onKey); + window.removeEventListener("scroll", onMove, true); + window.removeEventListener("resize", onMove); + }; + }, [bounds]); + if (!tooltip) + return errorProps ? cloneElement(children, errorProps) : children; + const above = + bounds && (placement === "top" || bounds.bottom > window.innerHeight - 100); + return ( + + {cloneElement(children, { + ...errorProps, + "aria-describedby": [ + children.props["aria-describedby"], + bounds ? id : undefined, + ] + .filter(Boolean) + .join(" "), + })} + {bounds && + createPortal( + , + document.body, + )} + + ); +}; diff --git a/web-app/src/i18n/lang.ts b/web-app/src/i18n/lang.ts index 3d8783f2d1..e5a1e94cb1 100644 --- a/web-app/src/i18n/lang.ts +++ b/web-app/src/i18n/lang.ts @@ -20,11 +20,22 @@ export const DEFAULT_LANG: Lang = "en"; const LANGUAGE_STORAGE_KEY = "language"; // Default is always English by design — no browser-language detection. -export const getStoredLanguage = (): Lang => - localStorage.getItem(LANGUAGE_STORAGE_KEY) === "zh" ? "zh" : DEFAULT_LANG; +export const getStoredLanguage = (): Lang => { + try { + return localStorage.getItem(LANGUAGE_STORAGE_KEY) === "zh" + ? "zh" + : DEFAULT_LANG; + } catch { + return DEFAULT_LANG; + } +}; export const storeLanguage = (lang: Lang) => { - localStorage.setItem(LANGUAGE_STORAGE_KEY, lang); + try { + localStorage.setItem(LANGUAGE_STORAGE_KEY, lang); + } catch { + // The current session still works when persistent storage is unavailable. + } }; // Precedence on duplicate keys: curated chrome (zh) > feature screens diff --git a/web-app/src/i18n/zhScreens.ts b/web-app/src/i18n/zhScreens.ts index ab34cc1731..2771e90df4 100644 --- a/web-app/src/i18n/zhScreens.ts +++ b/web-app/src/i18n/zhScreens.ts @@ -12,6 +12,54 @@ // then reconciled for glossary consistency; keep keys byte-identical to code. export const zhScreens: Record = { + "Sign Out": "登出", + "Manage bucket": "管理存储桶", + "Remove transfer": "移除传输记录", + "Cancel transfer": "取消传输", + "This download has already started. Dismiss its transfer entry to start it again.": + "此下载已开始。如需重新下载,请先移除对应的传输记录。", + "Track or cancel this download in your browser's download manager.": + "请在浏览器的下载管理器中查看进度或取消下载。", + "For selections above 5 GiB or of unknown size, MCLI is recommended. This ZIP will stream without buffering in memory.": + "超过 5 GiB 或大小未知的下载建议使用 MCLI。此 ZIP 将以流式传输,不会整包缓存在内存中。", + + "Unable to display this page.": "无法显示此页面。", + "Reload the page or return home. Your preferences will be kept.": + "请重新加载页面或返回首页。你的偏好设置将保留。", + "Reload page": "重新加载页面", + "Return home": "返回首页", + "404 Error": "404 错误", + "Sorry, the page could not be found.": "抱歉,找不到此页面。", + "Select multiple buckets": "选择多个存储桶", + "Select all buckets": "选择所有存储桶", + "Set lifecycle": "设置生命周期", + "Set replication": "设置复制", + "Refresh buckets": "刷新存储桶", + "Close details": "关闭详情", + "Copy share URL": "复制分享链接", + "Select multiple versions": "选择多个版本", + "Delete selected versions": "删除所选版本", + "Delete non-current versions": "删除非当前版本", + "Copy code": "复制代码", + "Delete group": "删除组", + "Refresh list": "刷新列表", + "Copy path": "复制路径", + "Delete user": "删除用户", + "Change password": "修改密码", + "Copy {label}": "复制{label}", + "Add site": "添加站点", + "Remove site": "移除站点", + "Delete selected users": "删除所选用户", + "View All": "查看全部", + "Deployment ID:": "部署 ID:", + "Request ID:": "请求 ID:", + "Remote host:": "远程主机:", + "User agent:": "用户代理:", + "Backtrace:": "调用栈:", + "Time:": "时间:", + "API:": "API:", + "Not available": "不可用", + " and ": " ", "'namespace' reflects current bucket/object list and 'access' reflects a journal of object operations, defaults to 'namespace'": "'namespace' 反映当前的存储桶/对象列表,'access' 反映对象操作的流水记录,默认为 'namespace'", diff --git a/web-app/src/index.css b/web-app/src/index.css index 262df31bbc..7de3c6bac0 100644 --- a/web-app/src/index.css +++ b/web-app/src/index.css @@ -275,16 +275,7 @@ html[lang="zh-CN"] #root .consoleTag { padding-left: 0.08em; } -/* Vendor-string overrides for zh: mds hardcodes a few labels ("Sign Out" in - the menu, "Actions:" in the object ActionsList). Their text nodes cannot be - reached via props, so swap them with CSS scoped to the zh locale. */ -html[lang="zh-CN"] #sign-out .labelContainer { - font-size: 0; -} -html[lang="zh-CN"] #sign-out .labelContainer::after { - content: "登出"; - font-size: 14px; -} +/* MDS ActionsList still exposes its heading only as a vendor string. */ html[lang="zh-CN"] #root ul.objectActions > li:first-of-type { font-size: 0; } @@ -293,3 +284,15 @@ html[lang="zh-CN"] #root ul.objectActions > li:first-of-type::after { font-size: 14px; font-weight: bold; } + +.recovery-page { + max-width: 44rem; + margin: 10vh auto; + padding: 2rem; + font-family: sans-serif; +} +.recovery-page button, +.recovery-page a { + font: inherit; + padding: 0.6rem; +} diff --git a/web-app/src/index.tsx b/web-app/src/index.tsx index fa7afd8468..904cdd74cc 100644 --- a/web-app/src/index.tsx +++ b/web-app/src/index.tsx @@ -20,6 +20,7 @@ import { Provider } from "react-redux"; import { store } from "./store"; import MainRouter from "./MainRouter"; import StyleHandler from "./StyleHandler"; +import RootErrorBoundary from "./common/RootErrorBoundary"; const root = ReactDOM.createRoot( document.getElementById("root") as HTMLElement, @@ -27,10 +28,12 @@ const root = ReactDOM.createRoot( root.render( - - - - - + + + + + + + , ); diff --git a/web-app/src/screens/Console/Buckets/BucketDetails/EnableBucketEncryption.tsx b/web-app/src/screens/Console/Buckets/BucketDetails/EnableBucketEncryption.tsx index 83fbe26d12..9233eb7607 100644 --- a/web-app/src/screens/Console/Buckets/BucketDetails/EnableBucketEncryption.tsx +++ b/web-app/src/screens/Console/Buckets/BucketDetails/EnableBucketEncryption.tsx @@ -211,6 +211,7 @@ const EnableBucketEncryption = ({ >