Compare commits

..

1 Commits

Author SHA1 Message Date
Armando Ruocco
3593c18f3f
fix(rbac): reconcile Role when ObjectStore spec changes
When an ObjectStore's credentials change (e.g., secret rename), the
RBAC Role granting the Cluster's ServiceAccount access to those secrets
was not updated because nothing triggered a Cluster reconciliation.

Implement the ObjectStore controller's Reconcile to detect referencing
Clusters and update their Roles directly. Extract ensureRole into a
shared rbac.EnsureRole function used by both the Pre hook and the
ObjectStore controller.

Handle concurrent modifications between the Pre hook and ObjectStore
controller gracefully: AlreadyExists on Create and Conflict on Patch
are retried once to avoid propagating transient errors as gRPC failures
to CNPG.

Replace the custom setOwnerReference helper (ownership.go) with
controllerutil.SetControllerReference for both Role and RoleBinding.
The old helper read the GVK from the object's metadata and replaced
all owner references unconditionally. The new function reads the GVK
from the scheme and appends to existing owner references, refusing to
overwrite if another controller already owns the object. Both produce
identical results for our use case since the Role is always freshly
built. The GVK is now resolved from the scheme configured via
CUSTOM_CNPG_GROUP/CUSTOM_CNPG_VERSION, which must match the actual
CNPG API group (same requirement as the instance sidecar).

Add dynamic CNPG scheme registration (internal/scheme) to the operator,
instance, and restore managers, replacing hardcoded cnpgv1.AddToScheme
calls. Add RBAC permission for the plugin to list/watch Clusters.

Signed-off-by: Armando Ruocco <armando.ruocco@enterprisedb.com>
2026-04-09 14:43:00 +02:00
17 changed files with 771 additions and 1505 deletions

View File

@ -37,7 +37,7 @@ jobs:
cache-dependency-path: web/yarn.lock
- name: Setup Pages
uses: actions/configure-pages@v6
uses: actions/configure-pages@v5
- name: Install dependencies
working-directory: web
@ -64,4 +64,4 @@ jobs:
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v5
uses: actions/deploy-pages@v4

View File

@ -46,7 +46,7 @@ tasks:
- wordlist-ordered
env:
# renovate: datasource=git-refs depName=spellcheck lookupName=https://github.com/cloudnative-pg/daggerverse currentValue=main
DAGGER_SPELLCHECK_SHA: 7003781e935b3cd4a8976e04179f660bac2d5603
DAGGER_SPELLCHECK_SHA: 9d731d14460bb9c71a9ad8f395e61bbda7d42449
cmds:
- >
GITHUB_REF= dagger -s call -m github.com/cloudnative-pg/daggerverse/spellcheck@${DAGGER_SPELLCHECK_SHA}
@ -60,7 +60,7 @@ tasks:
desc: Check for conventional commits
env:
# renovate: datasource=git-refs depName=commitlint lookupName=https://github.com/cloudnative-pg/daggerverse currentValue=main
DAGGER_COMMITLINT_SHA: 7003781e935b3cd4a8976e04179f660bac2d5603
DAGGER_COMMITLINT_SHA: 9d731d14460bb9c71a9ad8f395e61bbda7d42449
cmds:
- >
GITHUB_REF= dagger -s call -m github.com/cloudnative-pg/daggerverse/commitlint@${DAGGER_COMMITLINT_SHA}
@ -74,7 +74,7 @@ tasks:
- wordlist-ordered
env:
# renovate: datasource=git-refs depName=uncommitted lookupName=https://github.com/cloudnative-pg/daggerverse currentValue=main
DAGGER_UNCOMMITTED_SHA: 7003781e935b3cd4a8976e04179f660bac2d5603
DAGGER_UNCOMMITTED_SHA: 9d731d14460bb9c71a9ad8f395e61bbda7d42449
cmds:
- GITHUB_REF= dagger -s call -m github.com/cloudnative-pg/daggerverse/uncommitted@${DAGGER_UNCOMMITTED_SHA} check-uncommitted --source . stdout
sources:
@ -86,7 +86,7 @@ tasks:
- controller-gen
env:
# renovate: datasource=git-refs depName=crd-gen-refs lookupName=https://github.com/cloudnative-pg/daggerverse currentValue=main
DAGGER_CRDGENREF_SHA: 7003781e935b3cd4a8976e04179f660bac2d5603
DAGGER_CRDGENREF_SHA: 9d731d14460bb9c71a9ad8f395e61bbda7d42449
# renovate: datasource=go depName=github.com/elastic/crd-ref-docs
CRDREFDOCS_VERSION: v0.3.0
cmds:
@ -381,7 +381,7 @@ tasks:
run: once
env:
# renovate: datasource=git-refs depName=controller-gen lookupName=https://github.com/cloudnative-pg/daggerverse currentValue=main
DAGGER_CONTROLLER_GEN_SHA: 7003781e935b3cd4a8976e04179f660bac2d5603
DAGGER_CONTROLLER_GEN_SHA: 9d731d14460bb9c71a9ad8f395e61bbda7d42449
cmds:
- >
GITHUB_REF= dagger -s call -m github.com/cloudnative-pg/daggerverse/controller-gen@${DAGGER_CONTROLLER_GEN_SHA}

View File

@ -44,6 +44,7 @@ rules:
- postgresql.cnpg.io
resources:
- backups
- clusters
verbs:
- get
- list

View File

@ -4,15 +4,15 @@
#
# pip-compile --allow-unsafe --generate-hashes --output-file=sidecar-requirements.txt --strip-extras sidecar-requirements.in
#
azure-core==1.39.0 \
--hash=sha256:4ac7b70fab5438c3f68770649a78daf97833caa83827f91df9c14e0e0ea7d34f \
--hash=sha256:8a90a562998dd44ce84597590fff6249701b98c0e8797c95fcdd695b54c35d74
azure-core==1.38.2 \
--hash=sha256:074806c75cf239ea284a33a66827695ef7aeddac0b4e19dda266a93e4665ead9 \
--hash=sha256:67562857cb979217e48dc60980243b61ea115b77326fa93d83b729e7ff0482e7
# via
# azure-identity
# azure-storage-blob
azure-identity==1.25.3 \
--hash=sha256:ab23c0d63015f50b630ef6c6cf395e7262f439ce06e5d07a64e874c724f8d9e6 \
--hash=sha256:f4d0b956a8146f30333e071374171f3cfa7bdb8073adb8c3814b65567aa7447c
azure-identity==1.25.2 \
--hash=sha256:030dbaa720266c796221c6cdbd1999b408c079032c919fef725fcc348a540fe9 \
--hash=sha256:1b40060553d01a72ba0d708b9a46d0f61f56312e215d8896d836653ffdc6753d
# via barman
azure-storage-blob==12.28.0 \
--hash=sha256:00fb1db28bf6a7b7ecaa48e3b1d5c83bfadacc5a678b77826081304bd87d6461 \
@ -22,13 +22,13 @@ barman==3.18.0 \
--hash=sha256:8e752ac93d2f3a61e86b8374185209cae477a638ece7e6f540070f36d28d6997 \
--hash=sha256:ff90c44dafa4107b7574142771cdc2611c4cf1af818d93d3e67440a0c81164b9
# via -r sidecar-requirements.in
boto3==1.42.86 \
--hash=sha256:492c3c7cbbe9842882680064902f50cf711b5ab770d26525549872339ed95d5b \
--hash=sha256:c87d2a750b1a8cad0384d1a83d3bad6aedf924ae9a14aaba814bcb3297b39c01
boto3==1.42.63 \
--hash=sha256:cd008cfd0d7ea30f1c5e22daf0998c55b7c6c68cb68eea05110e33fe641173d5 \
--hash=sha256:d502a89a0acc701692ae020d15981f2a82e9eb3485acc651cfd0cf1a3afe79ee
# via barman
botocore==1.42.86 \
--hash=sha256:443387337864e069f7e4e885ccdc81592725b5598ca966514af3e9776bce0bfe \
--hash=sha256:baa49e93b4c92d63e0c8288026ee1ef8de83f182743127cc9175504440a48e49
botocore==1.42.63 \
--hash=sha256:1fdfc33cff58d21e8622cf620ba2bba3cff324557932aaf935b5374e4610f059 \
--hash=sha256:83f39d04f2b316bdfc59a3cac2d12238bde7126ac99d9a57d910dbd86d58c528
# via
# boto3
# s3transfer
@ -122,136 +122,120 @@ cffi==2.0.0 \
--hash=sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453 \
--hash=sha256:fe562eb1a64e67dd297ccc4f5addea2501664954f2692b69a76449ec7913ecbf
# via cryptography
charset-normalizer==3.4.7 \
--hash=sha256:007d05ec7321d12a40227aae9e2bc6dca73f3cb21058999a1df9e193555a9dcc \
--hash=sha256:03853ed82eeebbce3c2abfdbc98c96dc205f32a79627688ac9a27370ea61a49c \
--hash=sha256:07d9e39b01743c3717745f4c530a6349eadbfa043c7577eef86c502c15df2c67 \
--hash=sha256:08e721811161356f97b4059a9ba7bafb23ea5ee2255402c42881c214e173c6b4 \
--hash=sha256:0c96c3b819b5c3e9e165495db84d41914d6894d55181d2d108cc1a69bfc9cce0 \
--hash=sha256:0ea948db76d31190bf08bd371623927ee1339d5f2a0b4b1b4a4439a65298703c \
--hash=sha256:0f7eb884681e3938906ed0434f20c63046eacd0111c4ba96f27b76084cd679f5 \
--hash=sha256:12a6fff75f6bc66711b73a2f0addfc4c8c15a20e805146a02d147a318962c444 \
--hash=sha256:12d8baf840cc7889b37c7c770f478adea7adce3dcb3944d02ec87508e2dcf153 \
--hash=sha256:14265bfe1f09498b9d8ec91e9ec9fa52775edf90fcbde092b25f4a33d444fea9 \
--hash=sha256:16d971e29578a5e97d7117866d15889a4a07befe0e87e703ed63cd90cb348c01 \
--hash=sha256:177a0ba5f0211d488e295aaf82707237e331c24788d8d76c96c5a41594723217 \
--hash=sha256:1a87ca9d5df6fe460483d9a5bbf2b18f620cbed41b432e2bddb686228282d10b \
--hash=sha256:1c2a768fdd44ee4a9339a9b0b130049139b8ce3c01d2ce09f67f5a68048d477c \
--hash=sha256:1c2aed2e5e41f24ea8ef1590b8e848a79b56f3a5564a65ceec43c9d692dc7d8a \
--hash=sha256:1dc8b0ea451d6e69735094606991f32867807881400f808a106ee1d963c46a83 \
--hash=sha256:1efde3cae86c8c273f1eb3b287be7d8499420cf2fe7585c41d370d3e790054a5 \
--hash=sha256:202389074300232baeb53ae2569a60901f7efadd4245cf3a3bf0617d60b439d7 \
--hash=sha256:203104ed3e428044fd943bc4bf45fa73c0730391f9621e37fe39ecf477b128cb \
--hash=sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c \
--hash=sha256:298930cec56029e05497a76988377cbd7457ba864beeea92ad7e844fe74cd1f1 \
--hash=sha256:2cd4a60d0e2fb04537162c62bbbb4182f53541fe0ede35cdf270a1c1e723cc42 \
--hash=sha256:2d6eb928e13016cea4f1f21d1e10c1cebd5a421bc57ddf5b1142ae3f86824fab \
--hash=sha256:2fe249cb4651fd12605b7288b24751d8bfd46d35f12a20b1ba33dea122e690df \
--hash=sha256:30b8d1d8c52a48c2c5690e152c169b673487a2a58de1ec7393196753063fcd5e \
--hash=sha256:320ade88cfb846b8cd6b4ddf5ee9e80ee0c1f52401f2456b84ae1ae6a1a5f207 \
--hash=sha256:3534e7dcbdcf757da6b85a0bbf5b6868786d5982dd959b065e65481644817a18 \
--hash=sha256:36836d6ff945a00b88ba1e4572d721e60b5b8c98c155d465f56ad19d68f23734 \
--hash=sha256:38c0109396c4cfc574d502df99742a45c72c08eff0a36158b6f04000043dbf38 \
--hash=sha256:3946fa46a0cf3e4c8cb1cc52f56bb536310d34f25f01ca9b6c16afa767dab110 \
--hash=sha256:3bec022aec2c514d9cf199522a802bd007cd588ab17ab2525f20f9c34d067c18 \
--hash=sha256:3c9a494bc5ec77d43cea229c4f6db1e4d8fe7e1bbffa8b6f0f0032430ff8ab44 \
--hash=sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d \
--hash=sha256:3dedcc22d73ec993f42055eff4fcfed9318d1eeb9a6606c55892a26964964e48 \
--hash=sha256:4042d5c8f957e15221d423ba781e85d553722fc4113f523f2feb7b188cc34c5e \
--hash=sha256:481551899c856c704d58119b5025793fa6730adda3571971af568f66d2424bb5 \
--hash=sha256:4dc1e73c36828f982bfe79fadf5919923f8a6f4df2860804db9a98c48824ce8d \
--hash=sha256:4e5163c14bffd570ef2affbfdd77bba66383890797df43dc8b4cc7d6f500bf53 \
--hash=sha256:511ef87c8aec0783e08ac18565a16d435372bc1ac25a91e6ac7f5ef2b0bff790 \
--hash=sha256:532bc9bf33a68613fd7d65e4b1c71a6a38d7d42604ecf239c77392e9b4e8998c \
--hash=sha256:54523e136b8948060c0fa0bc7b1b50c32c186f2fceee897a495406bb6e311d2b \
--hash=sha256:5649fd1c7bade02f320a462fdefd0b4bd3ce036065836d4f42e0de958038e116 \
--hash=sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d \
--hash=sha256:5b77459df20e08151cd6f8b9ef8ef1f961ef73d85c21a555c7eed5b79410ec10 \
--hash=sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6 \
--hash=sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2 \
--hash=sha256:6370e8686f662e6a3941ee48ed4742317cafbe5707e36406e9df792cdb535776 \
--hash=sha256:64f02c6841d7d83f832cd97ccf8eb8a906d06eb95d5276069175c696b024b60a \
--hash=sha256:65bcd23054beab4d166035cabbc868a09c1a49d1efe458fe8e4361215df40265 \
--hash=sha256:66671f93accb62ed07da56613636f3641f1a12c13046ce91ffc923721f23c008 \
--hash=sha256:6696b7688f54f5af4462118f0bfa7c1621eeb87154f77fa04b9295ce7a8f2943 \
--hash=sha256:6785f414ae0f3c733c437e0f3929197934f526d19dfaa75e18fdb4f94c6fb374 \
--hash=sha256:67f6279d125ca0046a7fd386d01b311c6363844deac3e5b069b514ba3e63c246 \
--hash=sha256:6c114670c45346afedc0d947faf3c7f701051d2518b943679c8ff88befe14f8e \
--hash=sha256:6e0d51f618228538a3e8f46bd246f87a6cd030565e015803691603f55e12afb5 \
--hash=sha256:6ed74185b2db44f41ef35fd1617c5888e59792da9bbc9190d6c7300617182616 \
--hash=sha256:708838739abf24b2ceb208d0e22403dd018faeef86ddac04319a62ae884c4f15 \
--hash=sha256:715479b9a2802ecac752a3b0efa2b0b60285cf962ee38414211abdfccc233b41 \
--hash=sha256:733784b6d6def852c814bce5f318d25da2ee65dd4839a0718641c696e09a2960 \
--hash=sha256:750e02e074872a3fad7f233b47734166440af3cdea0add3e95163110816d6752 \
--hash=sha256:752a45dc4a6934060b3b0dab47e04edc3326575f82be64bc4fc293914566503e \
--hash=sha256:7579e913a5339fb8fa133f6bbcfd8e6749696206cf05acdbdca71a1b436d8e72 \
--hash=sha256:7641bb8895e77f921102f72833904dcd9901df5d6d72a2ab8f31d04b7e51e4e7 \
--hash=sha256:7804338df6fcc08105c7745f1502ba68d900f45fd770d5bdd5288ddccb8a42d8 \
--hash=sha256:80d04837f55fc81da168b98de4f4b797ef007fc8a79ab71c6ec9bc4dd662b15b \
--hash=sha256:813c0e0132266c08eb87469a642cb30aaff57c5f426255419572aaeceeaa7bf4 \
--hash=sha256:82b271f5137d07749f7bf32f70b17ab6eaabedd297e75dce75081a24f76eb545 \
--hash=sha256:84c018e49c3bf790f9c2771c45e9313a08c2c2a6342b162cd650258b57817706 \
--hash=sha256:8751d2787c9131302398b11e6c8068053dcb55d5a8964e114b6e196cf16cb366 \
--hash=sha256:8778f0c7a52e56f75d12dae53ae320fae900a8b9b4164b981b9c5ce059cd1fcb \
--hash=sha256:87fad7d9ba98c86bcb41b2dc8dbb326619be2562af1f8ff50776a39e55721c5a \
--hash=sha256:8d828b6667a32a728a1ad1d93957cdf37489c57b97ae6c4de2860fa749b8fc1e \
--hash=sha256:8e385e4267ab76874ae30db04c627faaaf0b509e1ccc11a95b3fc3e83f855c00 \
--hash=sha256:92a0a01ead5e668468e952e4238cccd7c537364eb7d851ab144ab6627dbbe12f \
--hash=sha256:94e1885b270625a9a828c9793b4d52a64445299baa1fea5a173bf1d3dd9a1a5a \
--hash=sha256:a180c5e59792af262bf263b21a3c49353f25945d8d9f70628e73de370d55e1e1 \
--hash=sha256:a277ab8928b9f299723bc1a2dabb1265911b1a76341f90a510368ca44ad9ab66 \
--hash=sha256:a5fe03b42827c13cdccd08e6c0247b6a6d4b5e3cdc53fd1749f5896adcdc2356 \
--hash=sha256:a6c5863edfbe888d9eff9c8b8087354e27618d9da76425c119293f11712a6319 \
--hash=sha256:a89c23ef8d2c6b27fd200a42aa4ac72786e7c60d40efdc76e6011260b6e949c4 \
--hash=sha256:adb2597b428735679446b46c8badf467b4ca5f5056aae4d51a19f9570301b1ad \
--hash=sha256:ae196f021b5e7c78e918242d217db021ed2a6ace2bc6ae94c0fc596221c7f58d \
--hash=sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5 \
--hash=sha256:aed52fea0513bac0ccde438c188c8a471c4e0f457c2dd20cdbf6ea7a450046c7 \
--hash=sha256:aef65cd602a6d0e0ff6f9930fcb1c8fec60dd2cfcb6facaf4bdb0e5873042db0 \
--hash=sha256:af21eb4409a119e365397b2adbaca4c9ccab56543a65d5dbd9f920d6ac29f686 \
--hash=sha256:b14b2d9dac08e28bb8046a1a0434b1750eb221c8f5b87a68f4fa11a6f97b5e34 \
--hash=sha256:bb6d88045545b26da47aa879dd4a89a71d1dce0f0e549b1abcb31dfe4a8eac49 \
--hash=sha256:bb8cc7534f51d9a017b93e3e85b260924f909601c3df002bcdb58ddb4dc41a5c \
--hash=sha256:bc17a677b21b3502a21f66a8cc64f5bfad4df8a0b8434d661666f8ce90ac3af1 \
--hash=sha256:bd6c2a1c7573c64738d716488d2cdd3c00e340e4835707d8fdb8dc1a66ef164e \
--hash=sha256:bd9b23791fe793e4968dba0c447e12f78e425c59fc0e3b97f6450f4781f3ee60 \
--hash=sha256:c03a41a8784091e67a39648f70c5f97b5b6a37f216896d44d2cdcb82615339a0 \
--hash=sha256:c0f081d69a6e58272819b70288d3221a6ee64b98df852631c80f293514d3b274 \
--hash=sha256:c35abb8bfff0185efac5878da64c45dafd2b37fb0383add1be155a763c1f083d \
--hash=sha256:c36c333c39be2dbca264d7803333c896ab8fa7d4d6f0ab7edb7dfd7aea6e98c0 \
--hash=sha256:c45e9440fb78f8ddabcf714b68f936737a121355bf59f3907f4e17721b9d1aae \
--hash=sha256:c593052c465475e64bbfe5dbd81680f64a67fdc752c56d7a0ae205dc8aeefe0f \
--hash=sha256:cdd68a1fb318e290a2077696b7eb7a21a49163c455979c639bf5a5dcdc46617d \
--hash=sha256:ce3412fbe1e31eb81ea42f4169ed94861c56e643189e1e75f0041f3fe7020abe \
--hash=sha256:cf1493cd8607bec4d8a7b9b004e699fcf8f9103a9284cc94962cb73d20f9d4a3 \
--hash=sha256:cf29836da5119f3c8a8a70667b0ef5fdca3bb12f80fd06487cfa575b3909b393 \
--hash=sha256:d4a48e5b3c2a489fae013b7589308a40146ee081f6f509e047e0e096084ceca1 \
--hash=sha256:d560742f3c0d62afaccf9f41fe485ed69bd7661a241f86a3ef0f0fb8b1a397af \
--hash=sha256:d6038d37043bced98a66e68d3aa2b6a35505dc01328cd65217cefe82f25def44 \
--hash=sha256:d61f00a0869d77422d9b2aba989e2d24afa6ffd552af442e0e58de4f35ea6d00 \
--hash=sha256:d635aab80466bc95771bb78d5370e74d36d1fe31467b6b29b8b57b2a3cd7d22c \
--hash=sha256:dca4bbc466a95ba9c0234ef56d7dd9509f63da22274589ebd4ed7f1f4d4c54e3 \
--hash=sha256:dd915403e231e6b1809fe9b6d9fc55cf8fb5e02765ac625d9cd623342a7905d7 \
--hash=sha256:e044c39e41b92c845bc815e5ae4230804e8e7bc29e399b0437d64222d92809dd \
--hash=sha256:e060d01aec0a910bdccb8be71faf34e7799ce36950f8294c8bf612cba65a2c9e \
--hash=sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b \
--hash=sha256:e17b8d5d6a8c47c85e68ca8379def1303fd360c3e22093a807cd34a71cd082b8 \
--hash=sha256:e5f4d355f0a2b1a31bc3edec6795b46324349c9cb25eed068049e4f472fb4259 \
--hash=sha256:e712b419df8ba5e42b226c510472b37bd57b38e897d3eca5e8cfd410a29fa859 \
--hash=sha256:e74327fb75de8986940def6e8dee4f127cc9752bee7355bb323cc5b2659b6d46 \
--hash=sha256:e80c8378d8f3d83cd3164da1ad2df9e37a666cdde7b1cb2298ed0b558064be30 \
--hash=sha256:e8ac484bf18ce6975760921bb6148041faa8fef0547200386ea0b52b5d27bf7b \
--hash=sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46 \
--hash=sha256:ed065083d0898c9d5b4bbec7b026fd755ff7454e6e8b73a67f8c744b13986e24 \
--hash=sha256:edac0f1ab77644605be2cbba52e6b7f630731fc42b34cb0f634be1a6eface56a \
--hash=sha256:effc3f449787117233702311a1b7d8f59cba9ced946ba727bdc329ec69028e24 \
--hash=sha256:f22dec1690b584cea26fade98b2435c132c1b5f68e39f5a0b7627cd7ae31f1dc \
--hash=sha256:f495a1652cf3fbab2eb0639776dad966c2fb874d79d87ca07f9d5f059b8bd215 \
--hash=sha256:f496c9c3cc02230093d8330875c4c3cdfc3b73612a5fd921c65d39cbcef08063 \
--hash=sha256:f59099f9b66f0d7145115e6f80dd8b1d847176df89b234a5a6b3f00437aa0832 \
--hash=sha256:f59ad4c0e8f6bba240a9bb85504faa1ab438237199d4cce5f622761507b8f6a6 \
--hash=sha256:fbccdc05410c9ee21bbf16a35f4c1d16123dcdeb8a1d38f33654fa21d0234f79 \
--hash=sha256:fea24543955a6a729c45a73fe90e08c743f0b3334bbf3201e6c4bc1b0c7fa464
charset-normalizer==3.4.5 \
--hash=sha256:014837af6fabf57121b6254fa8ade10dceabc3528b27b721a64bbc7b8b1d4eb4 \
--hash=sha256:01a1ed54b953303ca7e310fafe0fe347aab348bd81834a0bcd602eb538f89d66 \
--hash=sha256:0294916d6ccf2d069727d65973c3a1ca477d68708db25fd758dd28b0827cff54 \
--hash=sha256:02a9d1b01c1e12c27883b0c9349e0bcd9ae92e727ff1a277207e1a262b1cbf05 \
--hash=sha256:036c079aa08a6a592b82487f97c60b439428320ed1b2ea0b3912e99d30c77765 \
--hash=sha256:039215608ac7b358c4da0191d10fc76868567fbf276d54c14721bdedeb6de064 \
--hash=sha256:0625665e4ebdddb553ab185de5db7054393af8879fb0c87bd5690d14379d6819 \
--hash=sha256:0a45e504f5e1be0bd385935a8e1507c442349ca36f511a47057a71c9d1d6ea9e \
--hash=sha256:0b362bcd27819f9c07cbf23db4e0e8cd4b44c5ecd900c2ff907b2b92274a7412 \
--hash=sha256:0c300cefd9b0970381a46394902cd18eaf2aa00163f999590ace991989dcd0fc \
--hash=sha256:1088345bcc93c58d8d8f3d783eca4a6e7a7752bbff26c3eee7e73c597c191c2e \
--hash=sha256:10b473fc8dca1c3ad8559985794815f06ca3fc71942c969129070f2c3cdf7281 \
--hash=sha256:131716d6786ad5e3dc542f5cc6f397ba3339dc0fb87f87ac30e550e8987756af \
--hash=sha256:14498a429321de554b140013142abe7608f9d8ccc04d7baf2ad60498374aefa2 \
--hash=sha256:149ec69866c3d6c2fb6f758dbc014ecb09f30b35a5ca90b6a8a2d4e54e18fdfe \
--hash=sha256:165c7b21d19365464e8f70e5ce5e12524c58b48c78c1f5a57524603c1ab003f8 \
--hash=sha256:1827734a5b308b65ac54e86a618de66f935a4f63a8a462ff1e19a6788d6c2262 \
--hash=sha256:19092dde50335accf365cce21998a1c6dd8eafd42c7b226eb54b2747cdce2fac \
--hash=sha256:1a374cc0b88aa710e8865dc1bd6edb3743c59f27830f0293ab101e4cf3ce9f85 \
--hash=sha256:1d1401945cb77787dbd3af2446ff2d75912327c4c3a1526ab7955ecf8600687c \
--hash=sha256:1f2da5cbb9becfcd607757a169e38fb82aa5fd86fae6653dea716e7b613fe2cf \
--hash=sha256:259cd1ca995ad525f638e131dbcc2353a586564c038fc548a3fe450a91882139 \
--hash=sha256:2820a98460c83663dd8ec015d9ddfd1e4879f12e06bb7d0500f044fb477d2770 \
--hash=sha256:28269983f25a4da0425743d0d257a2d6921ea7d9b83599d4039486ec5b9f911d \
--hash=sha256:2b970382e4a36bed897c19f310f31d7d13489c11b4f468ddfba42d41cddfb918 \
--hash=sha256:2da4eedcb6338e2321e831a0165759c0c620e37f8cd044a263ff67493be8ffb3 \
--hash=sha256:30987f4a8ed169983f93e1be8ffeea5214a779e27ed0b059835c7afe96550ad7 \
--hash=sha256:30a2b1a48478c3428d047ed9690d57c23038dac838a87ad624c85c0a78ebeb39 \
--hash=sha256:340810d34ef83af92148e96e3e44cb2d3f910d2bf95e5618a5c467d9f102231d \
--hash=sha256:3f64c6bf8f32f9133b668c7f7a7cbdbc453412bc95ecdbd157f3b1e377a92990 \
--hash=sha256:4167a621a9a1a986c73777dbc15d4b5eac8ac5c10393374109a343d4013ec765 \
--hash=sha256:4354e401eb6dab9aed3c7b4030514328a6c748d05e1c3e19175008ca7de84fb1 \
--hash=sha256:4481e6da1830c8a1cc0b746b47f603b653dadb690bcd851d039ffaefe70533aa \
--hash=sha256:4b8551b6e6531e156db71193771c93bda78ffc4d1e6372517fe58ad3b91e4659 \
--hash=sha256:4cd966c2559f501c6fd69294d082c2934c8dd4719deb32c22961a5ac6db0df1d \
--hash=sha256:50bcbca6603c06a1dcc7b056ed45c37715fb5d2768feb3bcd37d2313c587a5b9 \
--hash=sha256:530beedcec9b6e027e7a4b6ce26eed36678aa39e17da85e6e03d7bd9e8e9d7c9 \
--hash=sha256:568e3c34b58422075a1b49575a6abc616d9751b4d61b23f712e12ebb78fe47b2 \
--hash=sha256:573ef5814c4b7c0d59a7710aa920eaaaef383bd71626aa420fba27b5cab92e8d \
--hash=sha256:58ad8270cfa5d4bef1bc85bd387217e14ff154d6630e976c6f56f9a040757475 \
--hash=sha256:597d10dec876923e5c59e48dbd366e852eacb2b806029491d307daea6b917d7c \
--hash=sha256:5bcb3227c3d9aaf73eaaab1db7ccd80a8995c509ee9941e2aae060ca6e4e5d81 \
--hash=sha256:5cffde4032a197bd3b42fd0b9509ec60fb70918d6970e4cc773f20fc9180ca67 \
--hash=sha256:5fea359734b140d0d6741189fea5478c6091b54ffc69d7ce119e0a05637d8c99 \
--hash=sha256:60d68e820af339df4ae8358c7a2e7596badeb61e544438e489035f9fbf3246a5 \
--hash=sha256:610f72c0ee565dfb8ae1241b666119582fdbfe7c0975c175be719f940e110694 \
--hash=sha256:65a126fb4b070d05340a84fc709dd9e7c75d9b063b610ece8a60197a291d0adf \
--hash=sha256:65b3c403a5b6b8034b655e7385de4f72b7b244869a22b32d4030b99a60593eca \
--hash=sha256:66dee73039277eb35380d1b82cccc69cc82b13a66f9f4a18da32d573acf02b7c \
--hash=sha256:708c7acde173eedd4bfa4028484426ba689d2103b28588c513b9db2cd5ecde9c \
--hash=sha256:728c6a963dfab66ef865f49286e45239384249672cd598576765acc2a640a636 \
--hash=sha256:754f96058e61a5e22e91483f823e07df16416ce76afa4ebf306f8e1d1296d43f \
--hash=sha256:75dfd1afe0b1647449e852f4fb428195a7ed0588947218f7ba929f6538487f02 \
--hash=sha256:75ee9c1cce2911581a70a3c0919d8bccf5b1cbc9b0e5171400ec736b4b569497 \
--hash=sha256:76a9d0de4d0eab387822e7b35d8f89367dd237c72e82ab42b9f7bf5e15ada00f \
--hash=sha256:77be992288f720306ab4108fe5c74797de327f3248368dfc7e1a916d6ed9e5a2 \
--hash=sha256:7ad83b8f9379176c841f8865884f3514d905bcd2a9a3b210eaa446e7d2223e4d \
--hash=sha256:8197abe5ca1ffb7d91e78360f915eef5addff270f8a71c1fc5be24a56f3e4873 \
--hash=sha256:82cc7c2ad42faec8b574351f8bc2a0c049043893853317bd9bb309f5aba6cb5a \
--hash=sha256:8a28afb04baa55abf26df544e3e5c6534245d3daa5178bc4a8eeb48202060d0e \
--hash=sha256:8b78d8a609a4b82c273257ee9d631ded7fac0d875bdcdccc109f3ee8328cfcb1 \
--hash=sha256:8ce11cd4d62d11166f2b441e30ace226c19a3899a7cf0796f668fba49a9fb123 \
--hash=sha256:8fff79bf5978c693c9b1a4d71e4a94fddfb5fe744eb062a318e15f4a2f63a550 \
--hash=sha256:92263f7eca2f4af326cd20de8d16728d2602f7cfea02e790dcde9d83c365d7cc \
--hash=sha256:93b3b2cc5cf1b8743660ce77a4f45f3f6d1172068207c1defc779a36eea6bb36 \
--hash=sha256:95adae7b6c42a6c5b5b559b1a99149f090a57128155daeea91732c8d970d8644 \
--hash=sha256:97ab7787092eb9b50fb47fa04f24c75b768a606af1bcba1957f07f128a7219e4 \
--hash=sha256:9db5e3fcdcee89a78c04dffb3fe33c79f77bd741a624946db2591c81b2fc85b0 \
--hash=sha256:a118e2e0b5ae6b0120d5efa5f866e58f2bb826067a646431da4d6a2bdae7950e \
--hash=sha256:a2aecdb364b8a1802afdc7f9327d55dad5366bc97d8502d0f5854e50712dbc5f \
--hash=sha256:a66aa5022bf81ab4b1bebfb009db4fd68e0c6d4307a1ce5ef6a26e5878dfc9e4 \
--hash=sha256:a68766a3c58fde7f9aaa22b3786276f62ab2f594efb02d0a1421b6282e852e98 \
--hash=sha256:aa2f963b4da26daf46231d9b9e0e2c9408a751f8f0d0f44d2de56d3caf51d294 \
--hash=sha256:aa92ec1102eaff840ccd1021478af176a831f1bccb08e526ce844b7ddda85c22 \
--hash=sha256:ac59c15e3f1465f722607800c68713f9fbc2f672b9eb649fe831da4019ae9b23 \
--hash=sha256:ae8b03427410731469c4033934cf473426faff3e04b69d2dfb64a4281a3719f8 \
--hash=sha256:afca7f78067dd27c2b848f1b234623d26b87529296c6c5652168cc1954f2f3b2 \
--hash=sha256:b2d37d78297b39a9eb9eb92c0f6df98c706467282055419df141389b23f93362 \
--hash=sha256:b3e71afc578b98512bfe7bdb822dd6bc57d4b0093b4b6e5487c1e96ad4ace242 \
--hash=sha256:ba20bdf69bd127f66d0174d6f2a93e69045e0b4036dc1ca78e091bcc765830c4 \
--hash=sha256:c108f8619e504140569ee7de3f97d234f0fbae338a7f9f360455071ef9855a95 \
--hash=sha256:c23eb3263356d94858655b3e63f85ac5d50970c6e8febcdde7830209139cc37d \
--hash=sha256:c5af897b45fa606b12464ccbe0014bbf8c09191e0a66aab6aa9d5cf6e77e0c94 \
--hash=sha256:c7a80a9242963416bd81f99349d5f3fce1843c303bd404f204918b6d75a75fd6 \
--hash=sha256:c7e84e0c0005e3bdc1a9211cd4e62c78ba80bc37b2365ef4410cd2007a9047f2 \
--hash=sha256:cace89841c0599d736d3d74a27bc5821288bb47c5441923277afc6059d7fbcb4 \
--hash=sha256:cd2d0f0ec9aa977a27731a3209ebbcacebebaf41f902bd453a928bfd281cf7f8 \
--hash=sha256:d01de5e768328646e6a3fa9e562706f8f6641708c115c62588aef2b941a4f88e \
--hash=sha256:d1028de43596a315e2720a9849ee79007ab742c06ad8b45a50db8cdb7ed4a82a \
--hash=sha256:d27ce22ec453564770d29d03a9506d449efbb9fa13c00842262b2f6801c48cce \
--hash=sha256:d29dd9c016f2078b43d0c357511e87eee5b05108f3dd603423cb389b89813969 \
--hash=sha256:d31f0d1671e1534e395f9eb84a68e0fb670e1edb1fe819a9d7f564ae3bc4e53f \
--hash=sha256:d4eb8ac7469b2a5d64b5b8c04f84d8bf3ad340f4514b98523805cbf46e3b3923 \
--hash=sha256:d5e52d127045d6ae01a1e821acfad2f3a1866c54d0e837828538fabe8d9d1bd6 \
--hash=sha256:d77f97e515688bd615c1d1f795d540f32542d514242067adcb8ef532504cb9ee \
--hash=sha256:d8ed79b8f6372ca4254955005830fd61c1ccdd8c0fac6603e2c145c61dd95db6 \
--hash=sha256:dc57a0baa3eeedd99fafaef7511b5a6ef4581494e8168ee086031744e2679467 \
--hash=sha256:e09f671a54ce70b79a1fc1dc6da3072b7ef7251fadb894ed92d9aa8218465a5f \
--hash=sha256:e22d1059b951e7ae7c20ef6b06afd10fb95e3c41bf3c4fbc874dba113321c193 \
--hash=sha256:e37bd100d2c5d3ba35db9c7c5ba5a9228cbcffe5c4778dc824b164e5257813d7 \
--hash=sha256:e51ae7d81c825761d941962450f50d041db028b7278e7b08930b4541b3e45cb9 \
--hash=sha256:e545b51da9f9af5c67815ca0eb40676c0f016d0b0381c86f20451e35696c5f95 \
--hash=sha256:e6302ca4ae283deb0af68d2fbf467474b8b6aedcd3dab4db187e07f94c109763 \
--hash=sha256:e71bbb595973622b817c042bd943c3f3667e9c9983ce3d205f973f486fec98a7 \
--hash=sha256:ec56a2266f32bc06ed3c3e2a8f58417ce02f7e0356edc89786e52db13c593c98 \
--hash=sha256:ed1a9a204f317ef879b32f9af507d47e49cd5e7f8e8d5d96358c98373314fc60 \
--hash=sha256:ed97c282ee4f994ef814042423a529df9497e3c666dca19be1d4cd1129dc7ade \
--hash=sha256:ed98364e1c262cf5f9363c3eca8c2df37024f52a8fa1180a3610014f26eac51c \
--hash=sha256:ee57b926940ba00bca7ba7041e665cc956e55ef482f851b9b65acb20d867e7a2 \
--hash=sha256:f1d725b754e967e648046f00c4facc42d414840f5ccc670c5670f59f83693e4f \
--hash=sha256:f8102ae93c0bc863b1d41ea0f4499c20a83229f52ed870850892df555187154a \
--hash=sha256:fc1c64934b8faf7584924143eb9db4770bbdb16659626e1a1a4d9efbcb68d947 \
--hash=sha256:ff95a9283de8a457e6b12989de3f9f5193430f375d64297d323a615ea52cbdb3
# via requests
cramjam==2.11.0 \
--hash=sha256:028400d699442d40dbda02f74158c73d05cb76587a12490d0bfedd958fd49188 \
@ -390,82 +374,82 @@ cramjam==2.11.0 \
# via
# barman
# python-snappy
cryptography==46.0.7 \
--hash=sha256:04959522f938493042d595a736e7dbdff6eb6cc2339c11465b3ff89343b65f65 \
--hash=sha256:128c5edfe5e5938b86b03941e94fac9ee793a94452ad1365c9fc3f4f62216832 \
--hash=sha256:1d25aee46d0c6f1a501adcddb2d2fee4b979381346a78558ed13e50aa8a59067 \
--hash=sha256:24402210aa54baae71d99441d15bb5a1919c195398a87b563df84468160a65de \
--hash=sha256:258514877e15963bd43b558917bc9f54cf7cf866c38aa576ebf47a77ddbc43a4 \
--hash=sha256:35719dc79d4730d30f1c2b6474bd6acda36ae2dfae1e3c16f2051f215df33ce0 \
--hash=sha256:397655da831414d165029da9bc483bed2fe0e75dde6a1523ec2fe63f3c46046b \
--hash=sha256:3986ac1dee6def53797289999eabe84798ad7817f3e97779b5061a95b0ee4968 \
--hash=sha256:420b1e4109cc95f0e5700eed79908cef9268265c773d3a66f7af1eef53d409ef \
--hash=sha256:42a1e5f98abb6391717978baf9f90dc28a743b7d9be7f0751a6f56a75d14065b \
--hash=sha256:462ad5cb1c148a22b2e3bcc5ad52504dff325d17daf5df8d88c17dda1f75f2a4 \
--hash=sha256:506c4ff91eff4f82bdac7633318a526b1d1309fc07ca76a3ad182cb5b686d6d3 \
--hash=sha256:5ad9ef796328c5e3c4ceed237a183f5d41d21150f972455a9d926593a1dcb308 \
--hash=sha256:5d1c02a14ceb9148cc7816249f64f623fbfee39e8c03b3650d842ad3f34d637e \
--hash=sha256:5e51be372b26ef4ba3de3c167cd3d1022934bc838ae9eaad7e644986d2a3d163 \
--hash=sha256:60627cf07e0d9274338521205899337c5d18249db56865f943cbe753aa96f40f \
--hash=sha256:65814c60f8cc400c63131584e3e1fad01235edba2614b61fbfbfa954082db0ee \
--hash=sha256:73510b83623e080a2c35c62c15298096e2a5dc8d51c3b4e1740211839d0dea77 \
--hash=sha256:7bbc6ccf49d05ac8f7d7b5e2e2c33830d4fe2061def88210a126d130d7f71a85 \
--hash=sha256:80406c3065e2c55d7f49a9550fe0c49b3f12e5bfff5dedb727e319e1afb9bf99 \
--hash=sha256:84d4cced91f0f159a7ddacad249cc077e63195c36aac40b4150e7a57e84fffe7 \
--hash=sha256:8a469028a86f12eb7d2fe97162d0634026d92a21f3ae0ac87ed1c4a447886c83 \
--hash=sha256:91bbcb08347344f810cbe49065914fe048949648f6bd5c2519f34619142bbe85 \
--hash=sha256:935ce7e3cfdb53e3536119a542b839bb94ec1ad081013e9ab9b7cfd478b05006 \
--hash=sha256:9694078c5d44c157ef3162e3bf3946510b857df5a3955458381d1c7cfc143ddb \
--hash=sha256:a1529d614f44b863a7b480c6d000fe93b59acee9c82ffa027cfadc77521a9f5e \
--hash=sha256:abad9dac36cbf55de6eb49badd4016806b3165d396f64925bf2999bcb67837ba \
--hash=sha256:b36a4695e29fe69215d75960b22577197aca3f7a25b9cf9d165dcfe9d80bc325 \
--hash=sha256:b7b412817be92117ec5ed95f880defe9cf18a832e8cafacf0a22337dc1981b4d \
--hash=sha256:c5b1ccd1239f48b7151a65bc6dd54bcfcc15e028c8ac126d3fada09db0e07ef1 \
--hash=sha256:cbd5fb06b62bd0721e1170273d3f4d5a277044c47ca27ee257025146c34cbdd1 \
--hash=sha256:cdf1a610ef82abb396451862739e3fc93b071c844399e15b90726ef7470eeaf2 \
--hash=sha256:cdfbe22376065ffcf8be74dc9a909f032df19bc58a699456a21712d6e5eabfd0 \
--hash=sha256:d02c738dacda7dc2a74d1b2b3177042009d5cab7c7079db74afc19e56ca1b455 \
--hash=sha256:d151173275e1728cf7839aaa80c34fe550c04ddb27b34f48c232193df8db5842 \
--hash=sha256:d23c8ca48e44ee015cd0a54aeccdf9f09004eba9fc96f38c911011d9ff1bd457 \
--hash=sha256:d3b99c535a9de0adced13d159c5a9cf65c325601aa30f4be08afd680643e9c15 \
--hash=sha256:d5f7520159cd9c2154eb61eb67548ca05c5774d39e9c2c4339fd793fe7d097b2 \
--hash=sha256:db0f493b9181c7820c8134437eb8b0b4792085d37dbb24da050476ccb664e59c \
--hash=sha256:e06acf3c99be55aa3b516397fe42f5855597f430add9c17fa46bf2e0fb34c9bb \
--hash=sha256:e4cfd68c5f3e0bfdad0d38e023239b96a2fe84146481852dffbcca442c245aa5 \
--hash=sha256:ea42cbe97209df307fdc3b155f1b6fa2577c0defa8f1f7d3be7d31d189108ad4 \
--hash=sha256:ebd6daf519b9f189f85c479427bbd6e9c9037862cf8fe89ee35503bd209ed902 \
--hash=sha256:f247c8c1a1fb45e12586afbb436ef21ff1e80670b2861a90353d9b025583d246 \
--hash=sha256:fbfd0e5f273877695cb93baf14b185f4878128b250cc9f8e617ea0c025dfb022 \
--hash=sha256:fc9ab8856ae6cf7c9358430e49b368f3108f050031442eaeb6b9d87e4dcf4e4f \
--hash=sha256:fcd8eac50d9138c1d7fc53a653ba60a2bee81a505f9f8850b6b2888555a45d0e \
--hash=sha256:fdd1736fed309b4300346f88f74cd120c27c56852c3838cab416e7a166f67298 \
--hash=sha256:ffca7aa1d00cf7d6469b988c581598f2259e46215e0140af408966a24cf086ce
cryptography==46.0.5 \
--hash=sha256:02f547fce831f5096c9a567fd41bc12ca8f11df260959ecc7c3202555cc47a72 \
--hash=sha256:039917b0dc418bb9f6edce8a906572d69e74bd330b0b3fea4f79dab7f8ddd235 \
--hash=sha256:1abfdb89b41c3be0365328a410baa9df3ff8a9110fb75e7b52e66803ddabc9a9 \
--hash=sha256:2ae6971afd6246710480e3f15824ed3029a60fc16991db250034efd0b9fb4356 \
--hash=sha256:2b7a67c9cd56372f3249b39699f2ad479f6991e62ea15800973b956f4b73e257 \
--hash=sha256:351695ada9ea9618b3500b490ad54c739860883df6c1f555e088eaf25b1bbaad \
--hash=sha256:38946c54b16c885c72c4f59846be9743d699eee2b69b6988e0a00a01f46a61a4 \
--hash=sha256:3b4995dc971c9fb83c25aa44cf45f02ba86f71ee600d81091c2f0cbae116b06c \
--hash=sha256:3ce58ba46e1bc2aac4f7d9290223cead56743fa6ab94a5d53292ffaac6a91614 \
--hash=sha256:3ee190460e2fbe447175cda91b88b84ae8322a104fc27766ad09428754a618ed \
--hash=sha256:4108d4c09fbbf2789d0c926eb4152ae1760d5a2d97612b92d508d96c861e4d31 \
--hash=sha256:420d0e909050490d04359e7fdb5ed7e667ca5c3c402b809ae2563d7e66a92229 \
--hash=sha256:47fb8a66058b80e509c47118ef8a75d14c455e81ac369050f20ba0d23e77fee0 \
--hash=sha256:4c3341037c136030cb46e4b1e17b7418ea4cbd9dd207e4a6f3b2b24e0d4ac731 \
--hash=sha256:4d7e3d356b8cd4ea5aff04f129d5f66ebdc7b6f8eae802b93739ed520c47c79b \
--hash=sha256:4d8ae8659ab18c65ced284993c2265910f6c9e650189d4e3f68445ef82a810e4 \
--hash=sha256:4e817a8920bfbcff8940ecfd60f23d01836408242b30f1a708d93198393a80b4 \
--hash=sha256:50bfb6925eff619c9c023b967d5b77a54e04256c4281b0e21336a130cd7fc263 \
--hash=sha256:556e106ee01aa13484ce9b0239bca667be5004efb0aabbed28d353df86445595 \
--hash=sha256:582f5fcd2afa31622f317f80426a027f30dc792e9c80ffee87b993200ea115f1 \
--hash=sha256:5be7bf2fb40769e05739dd0046e7b26f9d4670badc7b032d6ce4db64dddc0678 \
--hash=sha256:60ee7e19e95104d4c03871d7d7dfb3d22ef8a9b9c6778c94e1c8fcc8365afd48 \
--hash=sha256:61aa400dce22cb001a98014f647dc21cda08f7915ceb95df0c9eaf84b4b6af76 \
--hash=sha256:68f68d13f2e1cb95163fa3b4db4bf9a159a418f5f6e7242564fc75fcae667fd0 \
--hash=sha256:7d1f30a86d2757199cb2d56e48cce14deddf1f9c95f1ef1b64ee91ea43fe2e18 \
--hash=sha256:7d731d4b107030987fd61a7f8ab512b25b53cef8f233a97379ede116f30eb67d \
--hash=sha256:803812e111e75d1aa73690d2facc295eaefd4439be1023fefc4995eaea2af90d \
--hash=sha256:80a8d7bfdf38f87ca30a5391c0c9ce4ed2926918e017c29ddf643d0ed2778ea1 \
--hash=sha256:8293f3dea7fc929ef7240796ba231413afa7b68ce38fd21da2995549f5961981 \
--hash=sha256:8456928655f856c6e1533ff59d5be76578a7157224dbd9ce6872f25055ab9ab7 \
--hash=sha256:890bcb4abd5a2d3f852196437129eb3667d62630333aacc13dfd470fad3aaa82 \
--hash=sha256:94a76daa32eb78d61339aff7952ea819b1734b46f73646a07decb40e5b3448e2 \
--hash=sha256:9f16fbdf4da055efb21c22d81b89f155f02ba420558db21288b3d0035bafd5f4 \
--hash=sha256:a3d1fae9863299076f05cb8a778c467578262fae09f9dc0ee9b12eb4268ce663 \
--hash=sha256:a3d507bb6a513ca96ba84443226af944b0f7f47dcc9a399d110cd6146481d24c \
--hash=sha256:abace499247268e3757271b2f1e244b36b06f8515cf27c4d49468fc9eb16e93d \
--hash=sha256:ba2a27ff02f48193fc4daeadf8ad2590516fa3d0adeeb34336b96f7fa64c1e3a \
--hash=sha256:bc84e875994c3b445871ea7181d424588171efec3e185dced958dad9e001950a \
--hash=sha256:bfd56bb4b37ed4f330b82402f6f435845a5f5648edf1ad497da51a8452d5d62d \
--hash=sha256:c18ff11e86df2e28854939acde2d003f7984f721eba450b56a200ad90eeb0e6b \
--hash=sha256:c3bcce8521d785d510b2aad26ae2c966092b7daa8f45dd8f44734a104dc0bc1a \
--hash=sha256:c4143987a42a2397f2fc3b4d7e3a7d313fbe684f67ff443999e803dd75a76826 \
--hash=sha256:c69fd885df7d089548a42d5ec05be26050ebcd2283d89b3d30676eb32ff87dee \
--hash=sha256:ced80795227d70549a411a4ab66e8ce307899fad2220ce5ab2f296e687eacde9 \
--hash=sha256:d66e421495fdb797610a08f43b05269e0a5ea7f5e652a89bfd5a7d3c1dee3648 \
--hash=sha256:d861ee9e76ace6cf36a6a89b959ec08e7bc2493ee39d07ffe5acb23ef46d27da \
--hash=sha256:e9251e3be159d1020c4030bd2e5f84d6a43fe54b6c19c12f51cde9542a2817b2 \
--hash=sha256:f145bba11b878005c496e93e257c1e88f154d278d2638e6450d17e0f31e558d2 \
--hash=sha256:fe346b143ff9685e40192a4960938545c699054ba11d4f9029f94751e3f71d87
# via
# azure-identity
# azure-storage-blob
# google-auth
# msal
# pyjwt
google-api-core==2.30.2 \
--hash=sha256:9a8113e1a88bdc09a7ff629707f2214d98d61c7f6ceb0ea38c42a095d02dc0f9 \
--hash=sha256:a4c226766d6af2580577db1f1a51bf53cd262f722b49731ce7414c43068a9594
google-api-core==2.30.0 \
--hash=sha256:02edfa9fab31e17fc0befb5f161b3bf93c9096d99aed584625f38065c511ad9b \
--hash=sha256:80be49ee937ff9aba0fd79a6eddfde35fe658b9953ab9b79c57dd7061afa8df5
# via
# google-cloud-core
# google-cloud-storage
google-auth==2.49.1 \
--hash=sha256:16d40da1c3c5a0533f57d268fe72e0ebb0ae1cc3b567024122651c045d879b64 \
--hash=sha256:195ebe3dca18eddd1b3db5edc5189b76c13e96f29e73043b923ebcf3f1a860f7
google-auth==2.49.0 \
--hash=sha256:9cc2d9259d3700d7a257681f81052db6737495a1a46b610597f4b8bafe5286ae \
--hash=sha256:f893ef7307f19cf53700b7e2f61b5a6affe3aa0edf9943b13788920ab92d8d87
# via
# google-api-core
# google-cloud-core
# google-cloud-storage
google-cloud-core==2.5.1 \
--hash=sha256:3dc94bdec9d05a31d9f355045ed0f369fbc0d8c665076c734f065d729800f811 \
--hash=sha256:ea62cdf502c20e3e14be8a32c05ed02113d7bef454e40ff3fab6fe1ec9f1f4e7
google-cloud-core==2.5.0 \
--hash=sha256:67d977b41ae6c7211ee830c7912e41003ea8194bff15ae7d72fd6f51e57acabc \
--hash=sha256:7c1b7ef5c92311717bd05301aa1a91ffbc565673d3b0b4163a52d8413a186963
# via google-cloud-storage
google-cloud-storage==3.10.1 \
--hash=sha256:97db9aa4460727982040edd2bd13ff3d5e2260b5331ad22895802da1fc2a5286 \
--hash=sha256:a72f656759b7b99bda700f901adcb3425a828d4a29f911bc26b3ea79c5b1217f
google-cloud-storage==3.9.0 \
--hash=sha256:2dce75a9e8b3387078cbbdad44757d410ecdb916101f8ba308abf202b6968066 \
--hash=sha256:f2d8ca7db2f652be757e92573b2196e10fbc09649b5c016f8b422ad593c641cc
# via barman
google-crc32c==1.8.0 \
--hash=sha256:014a7e68d623e9a4222d663931febc3033c5c7c9730785727de2a81f87d5bab8 \
@ -504,13 +488,13 @@ google-crc32c==1.8.0 \
# via
# google-cloud-storage
# google-resumable-media
google-resumable-media==2.8.2 \
--hash=sha256:82b6d8ccd11765268cdd2a2123f417ec806b8eef3000a9a38dfe3033da5fb220 \
--hash=sha256:f3354a182ebd193ae3f42e3ef95e6c9b10f128320de23ac7637236713b1acd70
google-resumable-media==2.8.0 \
--hash=sha256:dd14a116af303845a8d932ddae161a26e86cc229645bc98b39f026f9b1717582 \
--hash=sha256:f1157ed8b46994d60a1bc432544db62352043113684d4e030ee02e77ebe9a1ae
# via google-cloud-storage
googleapis-common-protos==1.74.0 \
--hash=sha256:57971e4eeeba6aad1163c1f0fc88543f965bb49129b8bb55b2b7b26ecab084f1 \
--hash=sha256:702216f78610bb510e3f12ac3cafd281b7ac45cc5d86e90ad87e4d301a3426b5
googleapis-common-protos==1.73.0 \
--hash=sha256:778d07cd4fbeff84c6f7c72102f0daf98fa2bfd3fa8bea426edc545588da0b5a \
--hash=sha256:dfdaaa2e860f242046be561e6d6cb5c5f1541ae02cfbcb034371aadb2942b4e8
# via google-api-core
idna==3.11 \
--hash=sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea \
@ -585,9 +569,9 @@ lz4==4.4.5 \
--hash=sha256:f9b8bde9909a010c75b3aea58ec3910393b758f3c219beed67063693df854db0 \
--hash=sha256:ff1b50aeeec64df5603f17984e4b5be6166058dcf8f1e26a3da40d7a0f6ab547
# via barman
msal==1.36.0 \
--hash=sha256:36ecac30e2ff4322d956029aabce3c82301c29f0acb1ad89b94edcabb0e58ec4 \
--hash=sha256:3f6a4af2b036b476a4215111c4297b4e6e236ed186cd804faefba23e4990978b
msal==1.35.1 \
--hash=sha256:70cac18ab80a053bff86219ba64cfe3da1f307c74b009e2da57ef040eb1b5656 \
--hash=sha256:8f4e82f34b10c19e326ec69f44dc6b30171f2f7098f3720ea8a9f0c11832caa3
# via
# azure-identity
# msal-extensions
@ -595,19 +579,21 @@ msal-extensions==1.3.1 \
--hash=sha256:96d3de4d034504e969ac5e85bae8106c8373b5c6568e4c8fa7af2eca9dbe6bca \
--hash=sha256:c5b0fd10f65ef62b5f1d62f4251d51cbcaf003fcedae8c91b040a488614be1a4
# via azure-identity
proto-plus==1.27.2 \
--hash=sha256:6432f75893d3b9e70b9c412f1d2f03f65b11fb164b793d14ae2ca01821d22718 \
--hash=sha256:b2adde53adadf75737c44d3dcb0104fde65250dfc83ad59168b4aa3e574b6a24
proto-plus==1.27.1 \
--hash=sha256:912a7460446625b792f6448bade9e55cd4e41e6ac10e27009ef71a7f317fa147 \
--hash=sha256:e4643061f3a4d0de092d62aa4ad09fa4756b2cbb89d4627f3985018216f9fefc
# via google-api-core
protobuf==7.34.1 \
--hash=sha256:34b84ce27680df7cca9f231043ada0daa55d0c44a2ddfaa58ec1d0d89d8bf60a \
--hash=sha256:403b093a6e28a960372b44e5eb081775c9b056e816a8029c61231743d63f881a \
--hash=sha256:5185e0e948d07abe94bb76ec9b8416b604cfe5da6f871d67aad30cbf24c3110b \
--hash=sha256:8ff40ce8cd688f7265326b38d5a1bed9bfdf5e6723d49961432f83e21d5713e4 \
--hash=sha256:9ce42245e704cc5027be797c1db1eb93184d44d1cdd71811fb2d9b25ad541280 \
--hash=sha256:bb3812cd53aefea2b028ef42bd780f5b96407247f20c6ef7c679807e9d188f11 \
--hash=sha256:d8b2cc79c4d8f62b293ad9b11ec3aebce9af481fa73e64556969f7345ebf9fc7 \
--hash=sha256:e97b55646e6ce5cbb0954a8c28cd39a5869b59090dfaa7df4598a7fba869468c
protobuf==6.33.5 \
--hash=sha256:3093804752167bcab3998bec9f1048baae6e29505adaf1afd14a37bddede533c \
--hash=sha256:69915a973dd0f60f31a08b8318b73eab2bd6a392c79184b3612226b0a3f8ec02 \
--hash=sha256:6ddcac2a081f8b7b9642c09406bc6a4290128fce5f471cddd165960bb9119e5c \
--hash=sha256:8afa18e1d6d20af15b417e728e9f60f3aa108ee76f23c3b2c07a2c3b546d3afd \
--hash=sha256:8f04fa32763dcdb4973d537d6b54e615cc61108c7cb38fe59310c3192d29510a \
--hash=sha256:9b71e0281f36f179d00cbcb119cb19dec4d14a81393e5ea220f64b286173e190 \
--hash=sha256:a3157e62729aafb8df6da2c03aa5c0937c7266c626ce11a278b6eb7963c4e37c \
--hash=sha256:a5cb85982d95d906df1e2210e58f8e4f1e3cdc088e52c921a041f9c9a0386de5 \
--hash=sha256:cbf16ba3350fb7b889fca858fb215967792dc125b35c7976ca4818bee3521cf0 \
--hash=sha256:d71b040839446bac0f4d162e758bea99c8251161dae9d0983a3b88dee345153b
# via
# google-api-core
# googleapis-common-protos
@ -621,10 +607,12 @@ psycopg2==2.9.11 \
--hash=sha256:e03e4a6dbe87ff81540b434f2e5dc2bddad10296db5eea7bdc995bf5f4162938 \
--hash=sha256:f10a48acba5fe6e312b891f290b4d2ca595fc9a06850fe53320beac353575578
# via barman
pyasn1==0.6.3 \
--hash=sha256:697a8ecd6d98891189184ca1fa05d1bb00e2f84b5977c481452050549c8a72cf \
--hash=sha256:a80184d120f0864a52a073acc6fc642847d0be408e7c7252f31390c0f4eadcde
# via pyasn1-modules
pyasn1==0.6.2 \
--hash=sha256:1eb26d860996a18e9b6ed05e7aae0e9fc21619fcee6af91cca9bad4fbea224bf \
--hash=sha256:9b59a2b25ba7e4f8197db7686c09fb33e658b98339fadb826e9512629017833b
# via
# pyasn1-modules
# rsa
pyasn1-modules==0.4.2 \
--hash=sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a \
--hash=sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6
@ -633,9 +621,9 @@ pycparser==3.0 \
--hash=sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29 \
--hash=sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992
# via cffi
pyjwt==2.12.1 \
--hash=sha256:28ca37c070cad8ba8cd9790cd940535d40274d22f80ab87f3ac6a713e6e8454c \
--hash=sha256:c74a7a2adf861c04d002db713dd85f84beb242228e671280bf709d765b03672b
pyjwt==2.11.0 \
--hash=sha256:35f95c1f0fbe5d5ba6e43f00271c275f7a1a4db1dab27bf708073b75318ea623 \
--hash=sha256:94a6bde30eb5c8e04fee991062b534071fd1439ef58d2adc9ccb823e7bcd0469
# via
# msal
# pyjwt
@ -649,14 +637,18 @@ python-snappy==0.7.3 \
--hash=sha256:074c0636cfcd97e7251330f428064050ac81a52c62ed884fc2ddebbb60ed7f50 \
--hash=sha256:40216c1badfb2d38ac781ecb162a1d0ec40f8ee9747e610bcfefdfa79486cee3
# via barman
requests==2.33.1 \
--hash=sha256:18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517 \
--hash=sha256:4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a
requests==2.32.5 \
--hash=sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6 \
--hash=sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf
# via
# azure-core
# google-api-core
# google-cloud-storage
# msal
rsa==4.9.1 \
--hash=sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762 \
--hash=sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75
# via google-auth
s3transfer==0.16.0 \
--hash=sha256:18e25d66fed509e3868dc1572b3f427ff947dd2c56f844a5bf09481ad3f3b2fe \
--hash=sha256:8e990f13268025792229cd52fa10cb7163744bf56e719e0b9cb925ab79abf920

6
go.mod
View File

@ -2,11 +2,11 @@ module github.com/cloudnative-pg/plugin-barman-cloud
go 1.25.0
toolchain go1.26.2
toolchain go1.26.1
require (
github.com/cert-manager/cert-manager v1.20.1
github.com/cloudnative-pg/api v1.29.0
github.com/cloudnative-pg/api v1.28.1
github.com/cloudnative-pg/barman-cloud v0.5.0
github.com/cloudnative-pg/cloudnative-pg v1.29.0
github.com/cloudnative-pg/cnpg-i v0.5.0
@ -22,7 +22,7 @@ require (
k8s.io/apiextensions-apiserver v0.35.3
k8s.io/apimachinery v0.35.3
k8s.io/client-go v0.35.3
k8s.io/utils v0.0.0-20260319190234-28399d86e0b5
k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2
sigs.k8s.io/controller-runtime v0.23.3
sigs.k8s.io/kustomize/api v0.21.1
sigs.k8s.io/kustomize/kyaml v0.21.1

8
go.sum
View File

@ -18,8 +18,8 @@ github.com/cert-manager/cert-manager v1.20.1 h1:99ExHJu5TPp1V92AvvE4oY6BkOSyJiWL
github.com/cert-manager/cert-manager v1.20.1/go.mod h1:ut67FnggYJJqAdDWLhSPnj10P06QwbNU88RYNh9MvMc=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cloudnative-pg/api v1.29.0 h1:mNx6yJ5qi+Xrjs0NYrUy6V4MlXBkVJxGKwvTJZIuTX4=
github.com/cloudnative-pg/api v1.29.0/go.mod h1:bF3HI8UVVcllZ7M8CfBufnb+Us8FyQArhD+4qtX0qhM=
github.com/cloudnative-pg/api v1.28.1 h1:hp/TDgR+RrTa4EMp/pAKZia+kZ52i8ZPLG+JG10eeVU=
github.com/cloudnative-pg/api v1.28.1/go.mod h1:J0RTwrOYxQP17N1YMrDxcUmr/0wPYHQW179P7ibkVsM=
github.com/cloudnative-pg/barman-cloud v0.5.0 h1:DykSaX4o7ee2vyu5FQoG1RJsntHd+EIttIKZbJPlB1Q=
github.com/cloudnative-pg/barman-cloud v0.5.0/go.mod h1:SO2HzLa+GWlSIpGyxnISoJAFPIcaa/qDa33Bb3jefac=
github.com/cloudnative-pg/cloudnative-pg v1.29.0 h1:49Dm8+y4va7RODspJjeaK8uMWP3OGAD0gMsxhjm16Mo=
@ -328,8 +328,8 @@ k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc=
k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0=
k8s.io/kube-openapi v0.0.0-20260127142750-a19766b6e2d4 h1:HhDfevmPS+OalTjQRKbTHppRIz01AWi8s45TMXStgYY=
k8s.io/kube-openapi v0.0.0-20260127142750-a19766b6e2d4/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ=
k8s.io/utils v0.0.0-20260319190234-28399d86e0b5 h1:kBawHLSnx/mYHmRnNUf9d4CpjREbeZuxoSGOX/J+aYM=
k8s.io/utils v0.0.0-20260319190234-28399d86e0b5/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk=
k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 h1:AZYQSJemyQB5eRxqcPky+/7EdBj0xi3g0ZcxxJ7vbWU=
k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.33.0 h1:qPrZsv1cwQiFeieFlRqT627fVZ+tyfou/+S5S0H5ua0=
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.33.0/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
sigs.k8s.io/controller-runtime v0.23.3 h1:VjB/vhoPoA9l1kEKZHBMnQF33tdCLQKJtydy4iqwZ80=

View File

@ -81,8 +81,6 @@ func (c *CatalogMaintenanceRunnable) Start(ctx context.Context) error {
// cycle enforces the retention policies. On success, it returns the amount
// of time to wait to the next check.
func (c *CatalogMaintenanceRunnable) cycle(ctx context.Context) (time.Duration, error) {
contextLogger := log.FromContext(ctx)
var cluster cnpgv1.Cluster
var barmanObjectStore barmancloudv1.ObjectStore
@ -90,17 +88,7 @@ func (c *CatalogMaintenanceRunnable) cycle(ctx context.Context) (time.Duration,
return 0, err
}
enabledPlugins := cnpgv1.GetPluginConfigurationEnabledPluginNames(cluster.Spec.Plugins)
if !slices.Contains(enabledPlugins, metadata.PluginName) {
contextLogger.Debug("Skipping maintenance cycle: plugin is not enabled for backups")
return 0, nil
}
configuration := config.NewFromCluster(&cluster)
if configuration == nil || len(configuration.BarmanObjectName) == 0 {
return 0, fmt.Errorf("invalid configuration, missing barman object store reference")
}
if err := c.Client.Get(ctx, configuration.GetBarmanObjectKey(), &barmanObjectStore); err != nil {
return 0, err
}

View File

@ -26,10 +26,6 @@ import "github.com/cloudnative-pg/cnpg-i/pkg/identity"
const PluginName = "barman-cloud.cloudnative-pg.io"
const (
// ClusterLabelName is the label applied to RBAC resources created
// by this plugin. Its value is the name of the owning Cluster.
ClusterLabelName = "barmancloud.cnpg.io/cluster"
// CheckEmptyWalArchiveFile is the name of the file in the PGDATA that,
// if present, requires the WAL archiver to check that the backup object
// store is empty.

View File

@ -29,12 +29,10 @@ import (
rbacv1 "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/api/equality"
apierrs "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/client-go/util/retry"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/metadata"
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/specs"
)
@ -42,9 +40,10 @@ import (
// the desired state derived from the given ObjectStores. On creation,
// the Cluster is set as the owner of the Role for garbage collection.
//
// This function is called from the Pre hook (gRPC). It creates the
// Role if it does not exist, then patches rules and labels to match
// the desired state.
// This function is called from both the Pre hook (gRPC) and the
// ObjectStore controller. To handle concurrent modifications
// gracefully, AlreadyExists on Create and Conflict on Patch are
// retried once rather than returned as errors.
func EnsureRole(
ctx context.Context,
c client.Client,
@ -52,126 +51,108 @@ func EnsureRole(
barmanObjects []barmancloudv1.ObjectStore,
) error {
newRole := specs.BuildRole(cluster, barmanObjects)
roleKey := client.ObjectKeyFromObject(newRole)
if err := ensureRoleExists(ctx, c, cluster, newRole); err != nil {
roleKey := client.ObjectKey{
Namespace: newRole.Namespace,
Name: newRole.Name,
}
var role rbacv1.Role
err := c.Get(ctx, roleKey, &role)
switch {
case apierrs.IsNotFound(err):
role, err := createRole(ctx, c, cluster, newRole)
if err != nil {
return err
}
if role == nil {
// Created successfully, nothing else to do.
return nil
}
// AlreadyExists: fall through to patch with the re-read role.
return patchRoleRules(ctx, c, newRole.Rules, role)
case err != nil:
return err
}
return patchRole(ctx, c, roleKey, newRole.Rules, map[string]string{
metadata.ClusterLabelName: cluster.Name,
})
default:
return patchRoleRules(ctx, c, newRole.Rules, &role)
}
}
// EnsureRoleRules updates the rules of an existing Role to match
// the desired state derived from the given ObjectStores. Unlike
// EnsureRole, this function does not create Roles or set owner
// references — it only patches rules on Roles that already exist.
// It is intended for the ObjectStore controller path where no
// Cluster object is available. Returns nil if the Role does not
// exist (the Pre hook has not created it yet).
func EnsureRoleRules(
ctx context.Context,
c client.Client,
roleKey client.ObjectKey,
barmanObjects []barmancloudv1.ObjectStore,
) error {
err := patchRole(ctx, c, roleKey, specs.BuildRoleRules(barmanObjects), nil)
if apierrs.IsNotFound(err) {
log.FromContext(ctx).Debug("Role not found, skipping rule update",
"name", roleKey.Name, "namespace", roleKey.Namespace)
return nil
}
return err
}
// ensureRoleExists creates the Role if it does not exist. Returns
// nil on success and nil on AlreadyExists (another writer created
// it concurrently). The caller always follows up with patchRole.
func ensureRoleExists(
// createRole attempts to create the Role. If another writer created
// it concurrently (AlreadyExists), it re-reads and returns the
// existing Role for the caller to patch. On success it returns nil.
func createRole(
ctx context.Context,
c client.Client,
cluster *cnpgv1.Cluster,
newRole *rbacv1.Role,
) error {
) (*rbacv1.Role, error) {
contextLogger := log.FromContext(ctx)
var existing rbacv1.Role
err := c.Get(ctx, client.ObjectKeyFromObject(newRole), &existing)
if err == nil {
return nil
}
if !apierrs.IsNotFound(err) {
return err
}
if err := controllerutil.SetControllerReference(cluster, newRole, c.Scheme()); err != nil {
return err
return nil, err
}
contextLogger.Info("Creating role",
"name", newRole.Name, "namespace", newRole.Namespace)
createErr := c.Create(ctx, newRole)
if createErr == nil || apierrs.IsAlreadyExists(createErr) {
if createErr == nil {
return nil, nil
}
if !apierrs.IsAlreadyExists(createErr) {
return nil, createErr
}
contextLogger.Info("Role was created concurrently, checking rules")
var role rbacv1.Role
if err := c.Get(ctx, client.ObjectKeyFromObject(newRole), &role); err != nil {
return nil, err
}
return &role, nil
}
// patchRoleRules patches the Role's rules if they differ from the
// desired state. On Conflict (concurrent modification), it retries
// once with a fresh read.
func patchRoleRules(
ctx context.Context,
c client.Client,
desiredRules []rbacv1.PolicyRule,
role *rbacv1.Role,
) error {
if equality.Semantic.DeepEqual(desiredRules, role.Rules) {
return nil
}
return createErr
}
contextLogger := log.FromContext(ctx)
contextLogger.Info("Patching role",
"name", role.Name, "namespace", role.Namespace, "rules", desiredRules)
// patchRole patches the Role's rules and optionally its labels to
// match the desired state. When desiredLabels is nil, labels are
// not modified. Uses retry.RetryOnConflict for concurrent
// modification handling.
func patchRole(
ctx context.Context,
c client.Client,
roleKey client.ObjectKey,
desiredRules []rbacv1.PolicyRule,
desiredLabels map[string]string,
) error {
return retry.RetryOnConflict(retry.DefaultBackoff, func() error {
var role rbacv1.Role
if err := c.Get(ctx, roleKey, &role); err != nil {
return err
}
oldRole := role.DeepCopy()
role.Rules = desiredRules
rulesMatch := equality.Semantic.DeepEqual(desiredRules, role.Rules)
labelsMatch := desiredLabels == nil || !labelsNeedUpdate(role.Labels, desiredLabels)
if rulesMatch && labelsMatch {
return nil
}
contextLogger := log.FromContext(ctx)
contextLogger.Info("Patching role",
"name", role.Name, "namespace", role.Namespace)
oldRole := role.DeepCopy()
role.Rules = desiredRules
if desiredLabels != nil {
if role.Labels == nil {
role.Labels = make(map[string]string, len(desiredLabels))
}
for k, v := range desiredLabels {
role.Labels[k] = v
}
}
return c.Patch(ctx, &role, client.MergeFrom(oldRole))
})
}
// labelsNeedUpdate returns true if any key in desired is missing
// or has a different value in existing.
func labelsNeedUpdate(existing, desired map[string]string) bool {
for k, v := range desired {
if existing[k] != v {
return true
}
patchErr := c.Patch(ctx, role, client.MergeFrom(oldRole))
if patchErr == nil || !apierrs.IsConflict(patchErr) {
return patchErr
}
return false
// Conflict: re-read and retry once.
contextLogger.Info("Role was modified concurrently, retrying patch")
if err := c.Get(ctx, client.ObjectKeyFromObject(role), role); err != nil {
return err
}
if equality.Semantic.DeepEqual(desiredRules, role.Rules) {
return nil
}
oldRole = role.DeepCopy()
role.Rules = desiredRules
return c.Patch(ctx, role, client.MergeFrom(oldRole))
}

View File

@ -30,20 +30,18 @@ import (
rbacv1 "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/metadata"
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/rbac"
)
func newScheme() *runtime.Scheme {
s := runtime.NewScheme()
utilruntime.Must(rbacv1.AddToScheme(s))
utilruntime.Must(cnpgv1.AddToScheme(s))
utilruntime.Must(barmancloudv1.AddToScheme(s))
_ = rbacv1.AddToScheme(s)
_ = cnpgv1.AddToScheme(s)
_ = barmancloudv1.AddToScheme(s)
return s
}
@ -101,7 +99,7 @@ var _ = Describe("EnsureRole", func() {
fakeClient = fake.NewClientBuilder().WithScheme(newScheme()).Build()
})
It("should create the Role with owner reference and label", func() {
It("should create the Role with owner reference", func() {
err := rbac.EnsureRole(ctx, fakeClient, cluster, objects)
Expect(err).NotTo(HaveOccurred())
@ -113,11 +111,10 @@ var _ = Describe("EnsureRole", func() {
Expect(err).NotTo(HaveOccurred())
Expect(role.Rules).To(HaveLen(3))
// Verify owner reference is set to the Cluster
Expect(role.OwnerReferences).To(HaveLen(1))
Expect(role.OwnerReferences[0].Name).To(Equal("test-cluster"))
Expect(role.OwnerReferences[0].Kind).To(Equal("Cluster"))
Expect(role.Labels).To(HaveKeyWithValue(metadata.ClusterLabelName, "test-cluster"))
})
})
@ -170,133 +167,9 @@ var _ = Describe("EnsureRole", func() {
Expect(secretsRule.ResourceNames).To(ContainElement("aws-creds"))
Expect(secretsRule.ResourceNames).NotTo(ContainElement("old-secret"))
// Owner reference must survive the patch
Expect(role.OwnerReferences).To(HaveLen(1))
Expect(role.OwnerReferences[0].Name).To(Equal("test-cluster"))
})
})
Context("when the Role exists without the cluster label (upgrade scenario)", func() {
BeforeEach(func() {
fakeClient = fake.NewClientBuilder().WithScheme(newScheme()).Build()
// Create a Role without the label (simulates pre-upgrade state)
unlabeledRole := &rbacv1.Role{
ObjectMeta: metav1.ObjectMeta{
Name: "test-cluster-barman-cloud",
Namespace: "default",
},
Rules: []rbacv1.PolicyRule{},
}
Expect(fakeClient.Create(ctx, unlabeledRole)).To(Succeed())
})
It("should add the label and update rules", func() {
err := rbac.EnsureRole(ctx, fakeClient, cluster, objects)
Expect(err).NotTo(HaveOccurred())
var role rbacv1.Role
Expect(fakeClient.Get(ctx, client.ObjectKey{
Namespace: "default",
Name: "test-cluster-barman-cloud",
}, &role)).To(Succeed())
Expect(role.Labels).To(HaveKeyWithValue(metadata.ClusterLabelName, "test-cluster"))
Expect(role.Rules).To(HaveLen(3))
})
})
})
var _ = Describe("EnsureRoleRules", func() {
var (
ctx context.Context
fakeClient client.Client
objects []barmancloudv1.ObjectStore
)
BeforeEach(func() {
ctx = context.Background()
objects = []barmancloudv1.ObjectStore{
newObjectStore("my-store", "default", "aws-creds"),
}
})
Context("when the Role exists", func() {
BeforeEach(func() {
fakeClient = fake.NewClientBuilder().WithScheme(newScheme()).Build()
// Seed a labeled Role with old rules
cluster := newCluster("test-cluster", "default")
oldObjects := []barmancloudv1.ObjectStore{
newObjectStore("my-store", "default", "old-secret"),
}
Expect(rbac.EnsureRole(ctx, fakeClient, cluster, oldObjects)).To(Succeed())
})
It("should patch the rules", func() {
roleKey := client.ObjectKey{
Namespace: "default",
Name: "test-cluster-barman-cloud",
}
err := rbac.EnsureRoleRules(ctx, fakeClient, roleKey, objects)
Expect(err).NotTo(HaveOccurred())
var role rbacv1.Role
Expect(fakeClient.Get(ctx, roleKey, &role)).To(Succeed())
secretsRule := role.Rules[2]
Expect(secretsRule.ResourceNames).To(ContainElement("aws-creds"))
Expect(secretsRule.ResourceNames).NotTo(ContainElement("old-secret"))
})
It("should not patch when rules already match", func() {
// Seed with the same objects so rules match
cluster := newCluster("test-cluster", "default")
Expect(rbac.EnsureRole(ctx, fakeClient, cluster, objects)).To(Succeed())
roleKey := client.ObjectKey{
Namespace: "default",
Name: "test-cluster-barman-cloud",
}
var before rbacv1.Role
Expect(fakeClient.Get(ctx, roleKey, &before)).To(Succeed())
Expect(rbac.EnsureRoleRules(ctx, fakeClient, roleKey, objects)).To(Succeed())
var after rbacv1.Role
Expect(fakeClient.Get(ctx, roleKey, &after)).To(Succeed())
Expect(after.ResourceVersion).To(Equal(before.ResourceVersion))
})
It("should not modify labels", func() {
roleKey := client.ObjectKey{
Namespace: "default",
Name: "test-cluster-barman-cloud",
}
var before rbacv1.Role
Expect(fakeClient.Get(ctx, roleKey, &before)).To(Succeed())
Expect(rbac.EnsureRoleRules(ctx, fakeClient, roleKey, objects)).To(Succeed())
var after rbacv1.Role
Expect(fakeClient.Get(ctx, roleKey, &after)).To(Succeed())
Expect(after.Labels).To(Equal(before.Labels))
})
})
Context("when the Role does not exist", func() {
BeforeEach(func() {
fakeClient = fake.NewClientBuilder().WithScheme(newScheme()).Build()
})
It("should return nil", func() {
roleKey := client.ObjectKey{
Namespace: "default",
Name: "nonexistent-barman-cloud",
}
err := rbac.EnsureRoleRules(ctx, fakeClient, roleKey, objects)
Expect(err).NotTo(HaveOccurred())
})
})
})

View File

@ -21,7 +21,6 @@ package specs
import (
"fmt"
"slices"
cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
"github.com/cloudnative-pg/machinery/pkg/stringset"
@ -29,7 +28,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/metadata"
)
// BuildRole builds the Role object for this cluster
@ -37,20 +35,15 @@ func BuildRole(
cluster *cnpgv1.Cluster,
barmanObjects []barmancloudv1.ObjectStore,
) *rbacv1.Role {
return &rbacv1.Role{
role := &rbacv1.Role{
ObjectMeta: metav1.ObjectMeta{
Namespace: cluster.Namespace,
Name: GetRBACName(cluster.Name),
Labels: map[string]string{
metadata.ClusterLabelName: cluster.Name,
},
},
Rules: BuildRoleRules(barmanObjects),
}
}
// BuildRoleRules builds the RBAC PolicyRules for the given ObjectStores.
func BuildRoleRules(barmanObjects []barmancloudv1.ObjectStore) []rbacv1.PolicyRule {
Rules: []rbacv1.PolicyRule{},
}
secretsSet := stringset.New()
barmanObjectsSet := stringset.New()
@ -61,10 +54,11 @@ func BuildRoleRules(barmanObjects []barmancloudv1.ObjectStore) []rbacv1.PolicyRu
}
}
return []rbacv1.PolicyRule{
{
role.Rules = append(
role.Rules,
rbacv1.PolicyRule{
APIGroups: []string{
barmancloudv1.GroupVersion.Group,
"barmancloud.cnpg.io",
},
Verbs: []string{
"get",
@ -76,9 +70,9 @@ func BuildRoleRules(barmanObjects []barmancloudv1.ObjectStore) []rbacv1.PolicyRu
},
ResourceNames: barmanObjectsSet.ToSortedList(),
},
{
rbacv1.PolicyRule{
APIGroups: []string{
barmancloudv1.GroupVersion.Group,
"barmancloud.cnpg.io",
},
Verbs: []string{
"update",
@ -88,7 +82,7 @@ func BuildRoleRules(barmanObjects []barmancloudv1.ObjectStore) []rbacv1.PolicyRu
},
ResourceNames: barmanObjectsSet.ToSortedList(),
},
{
rbacv1.PolicyRule{
APIGroups: []string{
"",
},
@ -102,25 +96,9 @@ func BuildRoleRules(barmanObjects []barmancloudv1.ObjectStore) []rbacv1.PolicyRu
},
ResourceNames: secretsSet.ToSortedList(),
},
}
}
)
// ObjectStoreNamesFromRole extracts the ObjectStore names referenced
// by a plugin-managed Role. It finds the objectstores rule
// semantically (by APIGroup and Resource, not by index) and returns
// a copy of its ResourceNames. Returns nil if no matching rule is
// found.
func ObjectStoreNamesFromRole(role *rbacv1.Role) []string {
for _, rule := range role.Rules {
if len(rule.APIGroups) == 1 &&
rule.APIGroups[0] == barmancloudv1.GroupVersion.Group &&
len(rule.Resources) == 1 &&
rule.Resources[0] == "objectstores" {
return slices.Clone(rule.ResourceNames)
}
}
return nil
return role
}
// BuildRoleBinding builds the role binding object for this cluster

View File

@ -1,210 +0,0 @@
/*
Copyright © contributors to CloudNativePG, established as
CloudNativePG a Series of LF Projects, LLC.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
SPDX-License-Identifier: Apache-2.0
*/
package specs
import (
barmanapi "github.com/cloudnative-pg/barman-cloud/pkg/api"
cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
machineryapi "github.com/cloudnative-pg/machinery/pkg/api"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
rbacv1 "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/metadata"
)
func newTestObjectStore(name, secretName string) barmancloudv1.ObjectStore {
return barmancloudv1.ObjectStore{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: "default",
},
Spec: barmancloudv1.ObjectStoreSpec{
Configuration: barmanapi.BarmanObjectStoreConfiguration{
DestinationPath: "s3://bucket/path",
BarmanCredentials: barmanapi.BarmanCredentials{
AWS: &barmanapi.S3Credentials{
AccessKeyIDReference: &machineryapi.SecretKeySelector{
LocalObjectReference: machineryapi.LocalObjectReference{
Name: secretName,
},
Key: "ACCESS_KEY_ID",
},
},
},
},
},
}
}
var _ = Describe("BuildRoleRules", func() {
It("should produce 3 rules with correct ResourceNames", func() {
objects := []barmancloudv1.ObjectStore{
newTestObjectStore("store-a", "secret-a"),
newTestObjectStore("store-b", "secret-b"),
}
rules := BuildRoleRules(objects)
Expect(rules).To(HaveLen(3))
Expect(rules[0].APIGroups).To(Equal([]string{barmancloudv1.GroupVersion.Group}))
Expect(rules[0].Resources).To(Equal([]string{"objectstores"}))
Expect(rules[0].ResourceNames).To(ConsistOf("store-a", "store-b"))
Expect(rules[1].APIGroups).To(Equal([]string{barmancloudv1.GroupVersion.Group}))
Expect(rules[1].Resources).To(Equal([]string{"objectstores/status"}))
Expect(rules[1].ResourceNames).To(ConsistOf("store-a", "store-b"))
Expect(rules[2].APIGroups).To(Equal([]string{""}))
Expect(rules[2].Resources).To(Equal([]string{"secrets"}))
Expect(rules[2].ResourceNames).To(ConsistOf("secret-a", "secret-b"))
})
It("should produce rules with empty ResourceNames for empty input", func() {
rules := BuildRoleRules(nil)
Expect(rules).To(HaveLen(3))
Expect(rules[0].ResourceNames).To(BeEmpty())
Expect(rules[0].ResourceNames).NotTo(BeNil())
Expect(rules[1].ResourceNames).To(BeEmpty())
Expect(rules[2].ResourceNames).To(BeEmpty())
})
It("should deduplicate secret names across ObjectStores", func() {
objects := []barmancloudv1.ObjectStore{
newTestObjectStore("store-a", "shared-secret"),
newTestObjectStore("store-b", "shared-secret"),
}
rules := BuildRoleRules(objects)
Expect(rules[2].ResourceNames).To(Equal([]string{"shared-secret"}))
})
})
var _ = Describe("BuildRole", func() {
It("should set the cluster label", func() {
cluster := &cnpgv1.Cluster{
ObjectMeta: metav1.ObjectMeta{
Name: "my-cluster",
Namespace: "default",
},
}
role := BuildRole(cluster, nil)
Expect(role.Labels).To(HaveKeyWithValue(metadata.ClusterLabelName, "my-cluster"))
Expect(role.Name).To(Equal("my-cluster-barman-cloud"))
Expect(role.Namespace).To(Equal("default"))
})
})
var _ = Describe("BuildRoleRules / ObjectStoreNamesFromRole round-trip", func() {
It("should recover the same ObjectStore names from built rules", func() {
objects := []barmancloudv1.ObjectStore{
newTestObjectStore("store-a", "secret-a"),
newTestObjectStore("store-b", "secret-b"),
}
rules := BuildRoleRules(objects)
role := &rbacv1.Role{Rules: rules}
names := ObjectStoreNamesFromRole(role)
Expect(names).To(ConsistOf("store-a", "store-b"))
})
It("should recover empty names from rules built with no ObjectStores", func() {
rules := BuildRoleRules(nil)
role := &rbacv1.Role{Rules: rules}
names := ObjectStoreNamesFromRole(role)
Expect(names).To(BeEmpty())
})
})
var _ = Describe("ObjectStoreNamesFromRole", func() {
It("should extract ObjectStore names from a well-formed Role", func() {
role := &rbacv1.Role{
Rules: []rbacv1.PolicyRule{
{
APIGroups: []string{barmancloudv1.GroupVersion.Group},
Resources: []string{"objectstores"},
ResourceNames: []string{"store-a", "store-b"},
},
{
APIGroups: []string{""},
Resources: []string{"secrets"},
ResourceNames: []string{"secret-a"},
},
},
}
Expect(ObjectStoreNamesFromRole(role)).To(Equal([]string{"store-a", "store-b"}))
})
It("should return nil for a Role with no matching rule", func() {
role := &rbacv1.Role{
Rules: []rbacv1.PolicyRule{
{
APIGroups: []string{""},
Resources: []string{"secrets"},
ResourceNames: []string{"secret-a"},
},
},
}
Expect(ObjectStoreNamesFromRole(role)).To(BeNil())
})
It("should return nil for a Role with empty rules", func() {
role := &rbacv1.Role{}
Expect(ObjectStoreNamesFromRole(role)).To(BeNil())
})
It("should not match a rule with a different APIGroup", func() {
role := &rbacv1.Role{
Rules: []rbacv1.PolicyRule{
{
APIGroups: []string{"other.io"},
Resources: []string{"objectstores"},
ResourceNames: []string{"store-a"},
},
},
}
Expect(ObjectStoreNamesFromRole(role)).To(BeNil())
})
It("should not match a rule with multiple APIGroups", func() {
role := &rbacv1.Role{
Rules: []rbacv1.PolicyRule{
{
APIGroups: []string{barmancloudv1.GroupVersion.Group, "other.io"},
Resources: []string{"objectstores"},
ResourceNames: []string{"store-a"},
},
},
}
Expect(ObjectStoreNamesFromRole(role)).To(BeNil())
})
It("should not match a rule for objectstores/status", func() {
role := &rbacv1.Role{
Rules: []rbacv1.PolicyRule{
{
APIGroups: []string{barmancloudv1.GroupVersion.Group},
Resources: []string{"objectstores/status"},
ResourceNames: []string{"store-a"},
},
},
}
Expect(ObjectStoreNamesFromRole(role)).To(BeNil())
})
})

View File

@ -21,12 +21,10 @@ package controller
import (
"context"
"errors"
"fmt"
"slices"
cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
"github.com/cloudnative-pg/machinery/pkg/log"
rbacv1 "k8s.io/api/rbac/v1"
apierrs "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
@ -35,9 +33,8 @@ import (
"sigs.k8s.io/controller-runtime/pkg/predicate"
barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/metadata"
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/config"
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/rbac"
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/specs"
)
// ObjectStoreReconciler reconciles a ObjectStore object.
@ -49,16 +46,15 @@ type ObjectStoreReconciler struct {
// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=rolebindings,verbs=create;patch;update;get;list;watch
// +kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=roles,verbs=create;patch;update;get;list;watch
// +kubebuilder:rbac:groups="",resources=secrets,verbs=create;list;get;watch;delete
// +kubebuilder:rbac:groups=postgresql.cnpg.io,resources=backups,verbs=get;list;watch
// +kubebuilder:rbac:groups=postgresql.cnpg.io,resources=clusters,verbs=get;list;watch
// +kubebuilder:rbac:groups=postgresql.cnpg.io,resources=clusters/finalizers,verbs=update
// +kubebuilder:rbac:groups=postgresql.cnpg.io,resources=backups,verbs=get;list;watch
// +kubebuilder:rbac:groups=barmancloud.cnpg.io,resources=objectstores,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=barmancloud.cnpg.io,resources=objectstores/status,verbs=get;update;patch
// +kubebuilder:rbac:groups=barmancloud.cnpg.io,resources=objectstores/finalizers,verbs=update
// Reconcile ensures that the RBAC Role for each Cluster referencing
// this ObjectStore is up to date with the current ObjectStore spec.
// It discovers affected Roles by listing plugin-managed Roles and
// inspecting their rules, without needing access to Cluster objects.
func (r *ObjectStoreReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
contextLogger := log.FromContext(ctx).WithValues(
"objectStoreName", req.Name,
@ -68,64 +64,72 @@ func (r *ObjectStoreReconciler) Reconcile(ctx context.Context, req ctrl.Request)
contextLogger.Info("ObjectStore reconciliation start")
var roleList rbacv1.RoleList
if err := r.List(ctx, &roleList,
client.InNamespace(req.Namespace),
client.HasLabels{metadata.ClusterLabelName},
); err != nil {
return ctrl.Result{}, fmt.Errorf("while listing roles: %w", err)
// List all Clusters in the same namespace
var clusterList cnpgv1.ClusterList
if err := r.List(ctx, &clusterList, client.InNamespace(req.Namespace)); err != nil {
return ctrl.Result{}, fmt.Errorf("while listing clusters: %w", err)
}
var errs []error
for i := range roleList.Items {
role := &roleList.Items[i]
// For each Cluster that references this ObjectStore, reconcile the Role
for i := range clusterList.Items {
cluster := &clusterList.Items[i]
objectStoreNames := specs.ObjectStoreNamesFromRole(role)
if !slices.Contains(objectStoreNames, req.Name) {
pluginConfiguration := config.NewFromCluster(cluster)
referredObjects := pluginConfiguration.GetReferredBarmanObjectsKey()
if !referencesObjectStore(referredObjects, req.NamespacedName) {
continue
}
contextLogger.Info("Reconciling RBAC for role",
"roleName", role.Name)
contextLogger.Info("Reconciling RBAC for cluster",
"clusterName", cluster.Name)
if err := r.reconcileRoleRules(ctx, role, objectStoreNames); err != nil {
contextLogger.Error(err, "Failed to reconcile RBAC for role",
"roleName", role.Name)
errs = append(errs, fmt.Errorf("while reconciling role %s: %w", role.Name, err))
if err := r.reconcileRBACForCluster(ctx, cluster, referredObjects); err != nil {
return ctrl.Result{}, fmt.Errorf("while reconciling RBAC for cluster %s: %w", cluster.Name, err)
}
}
contextLogger.Info("ObjectStore reconciliation completed")
return ctrl.Result{}, errors.Join(errs...)
return ctrl.Result{}, nil
}
// reconcileRoleRules fetches the ObjectStores referenced by the
// Role and patches its rules to match the current specs.
func (r *ObjectStoreReconciler) reconcileRoleRules(
// reconcileRBACForCluster ensures the Role for the given Cluster is
// up to date with the current ObjectStore specs.
func (r *ObjectStoreReconciler) reconcileRBACForCluster(
ctx context.Context,
role *rbacv1.Role,
objectStoreNames []string,
cluster *cnpgv1.Cluster,
referredObjectKeys []client.ObjectKey,
) error {
contextLogger := log.FromContext(ctx)
barmanObjects := make([]barmancloudv1.ObjectStore, 0, len(objectStoreNames))
for _, name := range objectStoreNames {
barmanObjects := make([]barmancloudv1.ObjectStore, 0, len(referredObjectKeys))
for _, key := range referredObjectKeys {
var barmanObject barmancloudv1.ObjectStore
if err := r.Get(ctx, client.ObjectKey{
Namespace: role.Namespace,
Name: name,
}, &barmanObject); err != nil {
if err := r.Get(ctx, key, &barmanObject); err != nil {
if apierrs.IsNotFound(err) {
contextLogger.Info("ObjectStore not found, skipping",
"objectStoreName", name)
"objectStoreName", key.Name)
continue
}
return fmt.Errorf("while getting ObjectStore %s: %w", name, err)
return fmt.Errorf("while getting ObjectStore %s: %w", key, err)
}
barmanObjects = append(barmanObjects, barmanObject)
}
return rbac.EnsureRoleRules(ctx, r.Client, client.ObjectKeyFromObject(role), barmanObjects)
return rbac.EnsureRole(ctx, r.Client, cluster, barmanObjects)
}
// referencesObjectStore checks if the given ObjectStore is in the list
// of referred barman objects.
func referencesObjectStore(
referredObjects []client.ObjectKey,
objectStore client.ObjectKey,
) bool {
for _, ref := range referredObjects {
if ref.Name == objectStore.Name && ref.Namespace == objectStore.Namespace {
return true
}
}
return false
}
// SetupWithManager sets up the controller with the Manager.

View File

@ -22,6 +22,7 @@ package controller
import (
"context"
cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
barmanapi "github.com/cloudnative-pg/barman-cloud/pkg/api"
machineryapi "github.com/cloudnative-pg/machinery/pkg/api"
. "github.com/onsi/ginkgo/v2"
@ -29,7 +30,6 @@ import (
rbacv1 "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
@ -37,16 +37,35 @@ import (
barmancloudv1 "github.com/cloudnative-pg/plugin-barman-cloud/api/v1"
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/metadata"
"github.com/cloudnative-pg/plugin-barman-cloud/internal/cnpgi/operator/specs"
)
func newFakeScheme() *runtime.Scheme {
s := runtime.NewScheme()
utilruntime.Must(rbacv1.AddToScheme(s))
utilruntime.Must(barmancloudv1.AddToScheme(s))
_ = rbacv1.AddToScheme(s)
_ = cnpgv1.AddToScheme(s)
_ = barmancloudv1.AddToScheme(s)
return s
}
func newTestCluster(name, namespace, objectStoreName string) *cnpgv1.Cluster {
return &cnpgv1.Cluster{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
},
Spec: cnpgv1.ClusterSpec{
Plugins: []cnpgv1.PluginConfiguration{
{
Name: metadata.PluginName,
Parameters: map[string]string{
"barmanObjectName": objectStoreName,
},
},
},
},
}
}
func newTestObjectStore(name, namespace, secretName string) *barmancloudv1.ObjectStore {
return &barmancloudv1.ObjectStore{
ObjectMeta: metav1.ObjectMeta{
@ -71,23 +90,46 @@ func newTestObjectStore(name, namespace, secretName string) *barmancloudv1.Objec
}
}
func newLabeledRole(clusterName, namespace string, objectStores []barmancloudv1.ObjectStore) *rbacv1.Role {
return &rbacv1.Role{
ObjectMeta: metav1.ObjectMeta{
Name: specs.GetRBACName(clusterName),
Namespace: namespace,
Labels: map[string]string{
metadata.ClusterLabelName: clusterName,
},
},
Rules: specs.BuildRoleRules(objectStores),
}
}
var _ = Describe("referencesObjectStore", func() {
It("should return true when ObjectStore is in the list", func() {
refs := []client.ObjectKey{
{Name: "store-a", Namespace: "default"},
{Name: "store-b", Namespace: "default"},
}
Expect(referencesObjectStore(refs, client.ObjectKey{
Name: "store-b", Namespace: "default",
})).To(BeTrue())
})
It("should return false when ObjectStore is not in the list", func() {
refs := []client.ObjectKey{
{Name: "store-a", Namespace: "default"},
}
Expect(referencesObjectStore(refs, client.ObjectKey{
Name: "store-b", Namespace: "default",
})).To(BeFalse())
})
It("should return false when namespace differs", func() {
refs := []client.ObjectKey{
{Name: "store-a", Namespace: "ns1"},
}
Expect(referencesObjectStore(refs, client.ObjectKey{
Name: "store-a", Namespace: "ns2",
})).To(BeFalse())
})
It("should return false for empty list", func() {
Expect(referencesObjectStore(nil, client.ObjectKey{
Name: "store-a", Namespace: "default",
})).To(BeFalse())
})
})
var _ = Describe("ObjectStoreReconciler", func() {
var (
ctx context.Context
scheme *runtime.Scheme
ctx context.Context
scheme *runtime.Scheme
)
BeforeEach(func() {
@ -96,16 +138,13 @@ var _ = Describe("ObjectStoreReconciler", func() {
})
Describe("Reconcile", func() {
It("should update Role rules when ObjectStore credentials change", func() {
oldStore := newTestObjectStore("my-store", "default", "old-secret")
role := newLabeledRole("my-cluster", "default", []barmancloudv1.ObjectStore{*oldStore})
// Update the ObjectStore with new credentials
newStore := newTestObjectStore("my-store", "default", "new-secret")
It("should create a Role for a Cluster that references the ObjectStore", func() {
objectStore := newTestObjectStore("my-store", "default", "aws-creds")
cluster := newTestCluster("my-cluster", "default", "my-store")
fakeClient := fake.NewClientBuilder().
WithScheme(scheme).
WithObjects(role, newStore).
WithObjects(objectStore, cluster).
Build()
reconciler := &ObjectStoreReconciler{
@ -122,230 +161,162 @@ var _ = Describe("ObjectStoreReconciler", func() {
Expect(err).NotTo(HaveOccurred())
Expect(result).To(Equal(reconcile.Result{}))
var updatedRole rbacv1.Role
var role rbacv1.Role
err = fakeClient.Get(ctx, client.ObjectKey{
Namespace: "default",
Name: "my-cluster-barman-cloud",
}, &role)
Expect(err).NotTo(HaveOccurred())
Expect(role.Rules).To(HaveLen(3))
// Verify the secrets rule contains the expected secret
secretsRule := role.Rules[2]
Expect(secretsRule.ResourceNames).To(ContainElement("aws-creds"))
// Verify owner reference is set to the Cluster
Expect(role.OwnerReferences).To(HaveLen(1))
Expect(role.OwnerReferences[0].Name).To(Equal("my-cluster"))
Expect(role.OwnerReferences[0].Kind).To(Equal("Cluster"))
})
It("should skip Clusters that don't reference the ObjectStore", func() {
objectStore := newTestObjectStore("my-store", "default", "aws-creds")
cluster := newTestCluster("my-cluster", "default", "other-store")
fakeClient := fake.NewClientBuilder().
WithScheme(scheme).
WithObjects(objectStore, cluster).
Build()
reconciler := &ObjectStoreReconciler{
Client: fakeClient,
Scheme: scheme,
}
result, err := reconciler.Reconcile(ctx, reconcile.Request{
NamespacedName: types.NamespacedName{
Name: "my-store",
Namespace: "default",
},
})
Expect(err).NotTo(HaveOccurred())
Expect(result).To(Equal(reconcile.Result{}))
// No Role should have been created
var role rbacv1.Role
err = fakeClient.Get(ctx, client.ObjectKey{
Namespace: "default",
Name: "my-cluster-barman-cloud",
}, &role)
Expect(err).To(HaveOccurred())
})
It("should succeed with no Clusters in the namespace", func() {
fakeClient := fake.NewClientBuilder().
WithScheme(scheme).
Build()
reconciler := &ObjectStoreReconciler{
Client: fakeClient,
Scheme: scheme,
}
result, err := reconciler.Reconcile(ctx, reconcile.Request{
NamespacedName: types.NamespacedName{
Name: "my-store",
Namespace: "default",
},
})
Expect(err).NotTo(HaveOccurred())
Expect(result).To(Equal(reconcile.Result{}))
})
})
Describe("reconcileRBACForCluster", func() {
It("should skip deleted ObjectStores and still reconcile the Role", func() {
// Cluster references two ObjectStores, but one is deleted
cluster := newTestCluster("my-cluster", "default", "store-a")
existingStore := newTestObjectStore("store-a", "default", "aws-creds")
fakeClient := fake.NewClientBuilder().
WithScheme(scheme).
WithObjects(existingStore).
Build()
reconciler := &ObjectStoreReconciler{
Client: fakeClient,
Scheme: scheme,
}
// Pass two keys, but "store-b" doesn't exist
err := reconciler.reconcileRBACForCluster(ctx, cluster, []client.ObjectKey{
{Name: "store-a", Namespace: "default"},
{Name: "store-b", Namespace: "default"},
})
Expect(err).NotTo(HaveOccurred())
// Role should be created with only store-a's secrets
var role rbacv1.Role
err = fakeClient.Get(ctx, client.ObjectKey{
Namespace: "default",
Name: "my-cluster-barman-cloud",
}, &role)
Expect(err).NotTo(HaveOccurred())
Expect(role.Rules).To(HaveLen(3))
// ObjectStore rule should only reference store-a
objectStoreRule := role.Rules[0]
Expect(objectStoreRule.ResourceNames).To(ContainElement("store-a"))
Expect(objectStoreRule.ResourceNames).NotTo(ContainElement("store-b"))
// Verify owner reference is set
Expect(role.OwnerReferences).To(HaveLen(1))
Expect(role.OwnerReferences[0].Name).To(Equal("my-cluster"))
})
It("should update Role when ObjectStore credentials change", func() {
cluster := newTestCluster("my-cluster", "default", "my-store")
oldStore := newTestObjectStore("my-store", "default", "old-secret")
fakeClient := fake.NewClientBuilder().
WithScheme(scheme).
WithObjects(oldStore).
Build()
reconciler := &ObjectStoreReconciler{
Client: fakeClient,
Scheme: scheme,
}
// First reconcile - creates Role with old-secret
err := reconciler.reconcileRBACForCluster(ctx, cluster, []client.ObjectKey{
{Name: "my-store", Namespace: "default"},
})
Expect(err).NotTo(HaveOccurred())
// Update the ObjectStore with new credentials
var currentStore barmancloudv1.ObjectStore
Expect(fakeClient.Get(ctx, client.ObjectKey{
Name: "my-store", Namespace: "default",
}, &currentStore)).To(Succeed())
currentStore.Spec.Configuration.BarmanCredentials.AWS.AccessKeyIDReference.LocalObjectReference.Name = "new-secret"
Expect(fakeClient.Update(ctx, &currentStore)).To(Succeed())
// Second reconcile - should patch Role with new-secret
err = reconciler.reconcileRBACForCluster(ctx, cluster, []client.ObjectKey{
{Name: "my-store", Namespace: "default"},
})
Expect(err).NotTo(HaveOccurred())
var role rbacv1.Role
Expect(fakeClient.Get(ctx, client.ObjectKey{
Namespace: "default",
Name: "my-cluster-barman-cloud",
}, &updatedRole)).To(Succeed())
}, &role)).To(Succeed())
secretsRule := updatedRole.Rules[2]
secretsRule := role.Rules[2]
Expect(secretsRule.ResourceNames).To(ContainElement("new-secret"))
Expect(secretsRule.ResourceNames).NotTo(ContainElement("old-secret"))
})
It("should skip Roles that don't reference the ObjectStore", func() {
otherStore := newTestObjectStore("other-store", "default", "other-creds")
role := newLabeledRole("my-cluster", "default", []barmancloudv1.ObjectStore{*otherStore})
fakeClient := fake.NewClientBuilder().
WithScheme(scheme).
WithObjects(role).
Build()
reconciler := &ObjectStoreReconciler{
Client: fakeClient,
Scheme: scheme,
}
var before rbacv1.Role
Expect(fakeClient.Get(ctx, client.ObjectKey{
Namespace: "default",
Name: "my-cluster-barman-cloud",
}, &before)).To(Succeed())
result, err := reconciler.Reconcile(ctx, reconcile.Request{
NamespacedName: types.NamespacedName{
Name: "unrelated-store",
Namespace: "default",
},
})
Expect(err).NotTo(HaveOccurred())
Expect(result).To(Equal(reconcile.Result{}))
var after rbacv1.Role
Expect(fakeClient.Get(ctx, client.ObjectKey{
Namespace: "default",
Name: "my-cluster-barman-cloud",
}, &after)).To(Succeed())
Expect(after.ResourceVersion).To(Equal(before.ResourceVersion))
})
It("should succeed with no labeled Roles in the namespace", func() {
fakeClient := fake.NewClientBuilder().
WithScheme(scheme).
Build()
reconciler := &ObjectStoreReconciler{
Client: fakeClient,
Scheme: scheme,
}
result, err := reconciler.Reconcile(ctx, reconcile.Request{
NamespacedName: types.NamespacedName{
Name: "my-store",
Namespace: "default",
},
})
Expect(err).NotTo(HaveOccurred())
Expect(result).To(Equal(reconcile.Result{}))
})
It("should handle deleted ObjectStores gracefully", func() {
storeA := newTestObjectStore("store-a", "default", "secret-a")
storeB := newTestObjectStore("store-b", "default", "secret-b")
role := newLabeledRole("my-cluster", "default", []barmancloudv1.ObjectStore{*storeA, *storeB})
// Only store-a exists; store-b was deleted
fakeClient := fake.NewClientBuilder().
WithScheme(scheme).
WithObjects(role, storeA).
Build()
reconciler := &ObjectStoreReconciler{
Client: fakeClient,
Scheme: scheme,
}
result, err := reconciler.Reconcile(ctx, reconcile.Request{
NamespacedName: types.NamespacedName{
Name: "store-b",
Namespace: "default",
},
})
Expect(err).NotTo(HaveOccurred())
Expect(result).To(Equal(reconcile.Result{}))
var updatedRole rbacv1.Role
Expect(fakeClient.Get(ctx, client.ObjectKey{
Namespace: "default",
Name: "my-cluster-barman-cloud",
}, &updatedRole)).To(Succeed())
objectStoreRule := updatedRole.Rules[0]
Expect(objectStoreRule.ResourceNames).To(ContainElement("store-a"))
Expect(objectStoreRule.ResourceNames).NotTo(ContainElement("store-b"))
})
It("should not panic on a Role with empty rules", func() {
emptyRole := &rbacv1.Role{
ObjectMeta: metav1.ObjectMeta{
Name: "empty-barman-cloud",
Namespace: "default",
Labels: map[string]string{
metadata.ClusterLabelName: "empty",
},
},
}
fakeClient := fake.NewClientBuilder().
WithScheme(scheme).
WithObjects(emptyRole).
Build()
reconciler := &ObjectStoreReconciler{
Client: fakeClient,
Scheme: scheme,
}
result, err := reconciler.Reconcile(ctx, reconcile.Request{
NamespacedName: types.NamespacedName{
Name: "my-store",
Namespace: "default",
},
})
Expect(err).NotTo(HaveOccurred())
Expect(result).To(Equal(reconcile.Result{}))
})
It("should produce empty ResourceNames when all ObjectStores are deleted", func() {
store := newTestObjectStore("my-store", "default", "aws-creds")
role := newLabeledRole("my-cluster", "default", []barmancloudv1.ObjectStore{*store})
// Don't add the ObjectStore to the fake client (simulates deletion)
fakeClient := fake.NewClientBuilder().
WithScheme(scheme).
WithObjects(role).
Build()
reconciler := &ObjectStoreReconciler{
Client: fakeClient,
Scheme: scheme,
}
result, err := reconciler.Reconcile(ctx, reconcile.Request{
NamespacedName: types.NamespacedName{
Name: "my-store",
Namespace: "default",
},
})
Expect(err).NotTo(HaveOccurred())
Expect(result).To(Equal(reconcile.Result{}))
var updatedRole rbacv1.Role
Expect(fakeClient.Get(ctx, client.ObjectKey{
Namespace: "default",
Name: "my-cluster-barman-cloud",
}, &updatedRole)).To(Succeed())
// All rules should have empty ResourceNames
Expect(updatedRole.Rules[0].ResourceNames).To(BeEmpty())
Expect(updatedRole.Rules[1].ResourceNames).To(BeEmpty())
Expect(updatedRole.Rules[2].ResourceNames).To(BeEmpty())
})
It("should reconcile multiple Roles referencing the same ObjectStore", func() {
store := newTestObjectStore("shared-store", "default", "new-secret")
oldStore := barmancloudv1.ObjectStore{
ObjectMeta: metav1.ObjectMeta{Name: "shared-store", Namespace: "default"},
Spec: barmancloudv1.ObjectStoreSpec{
Configuration: barmanapi.BarmanObjectStoreConfiguration{
DestinationPath: "s3://bucket/path",
BarmanCredentials: barmanapi.BarmanCredentials{
AWS: &barmanapi.S3Credentials{
AccessKeyIDReference: &machineryapi.SecretKeySelector{
LocalObjectReference: machineryapi.LocalObjectReference{Name: "old-secret"},
Key: "ACCESS_KEY_ID",
},
},
},
},
},
}
role1 := newLabeledRole("cluster-1", "default", []barmancloudv1.ObjectStore{oldStore})
role2 := newLabeledRole("cluster-2", "default", []barmancloudv1.ObjectStore{oldStore})
fakeClient := fake.NewClientBuilder().
WithScheme(scheme).
WithObjects(role1, role2, store).
Build()
reconciler := &ObjectStoreReconciler{
Client: fakeClient,
Scheme: scheme,
}
result, err := reconciler.Reconcile(ctx, reconcile.Request{
NamespacedName: types.NamespacedName{
Name: "shared-store",
Namespace: "default",
},
})
Expect(err).NotTo(HaveOccurred())
Expect(result).To(Equal(reconcile.Result{}))
for _, clusterName := range []string{"cluster-1", "cluster-2"} {
var updatedRole rbacv1.Role
Expect(fakeClient.Get(ctx, client.ObjectKey{
Namespace: "default",
Name: specs.GetRBACName(clusterName),
}, &updatedRole)).To(Succeed())
secretsRule := updatedRole.Rules[2]
Expect(secretsRule.ResourceNames).To(ContainElement("new-secret"))
Expect(secretsRule.ResourceNames).NotTo(ContainElement("old-secret"))
}
})
})
})

View File

@ -870,6 +870,7 @@ rules:
- postgresql.cnpg.io
resources:
- backups
- clusters
verbs:
- get
- list

View File

@ -15,8 +15,8 @@
"typecheck": "tsc"
},
"dependencies": {
"@docusaurus/core": "3.10.0",
"@docusaurus/preset-classic": "3.10.0",
"@docusaurus/core": "3.9.2",
"@docusaurus/preset-classic": "3.9.2",
"@easyops-cn/docusaurus-search-local": "^0.55.0",
"@mdx-js/react": "^3.0.0",
"clsx": "^2.0.0",
@ -25,10 +25,10 @@
"react-dom": "^19.0.0"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "3.10.0",
"@docusaurus/tsconfig": "3.10.0",
"@docusaurus/types": "3.10.0",
"typescript": "~6.0.0"
"@docusaurus/module-type-aliases": "3.9.2",
"@docusaurus/tsconfig": "3.9.2",
"@docusaurus/types": "3.9.2",
"typescript": "~5.9.0"
},
"browserslist": {
"production": [

View File

@ -20,14 +20,6 @@
"@algolia/autocomplete-plugin-algolia-insights" "1.19.2"
"@algolia/autocomplete-shared" "1.19.2"
"@algolia/autocomplete-core@^1.19.2":
version "1.19.8"
resolved "https://registry.yarnpkg.com/@algolia/autocomplete-core/-/autocomplete-core-1.19.8.tgz#7c84c771d28643fb00d09026c05013fb97aeea23"
integrity sha512-3YEorYg44niXcm7gkft3nXYItHd44e8tmh4D33CTszPgP0QWkaLEaFywiNyJBo7UL/mqObA/G9RYuU7R8tN1IA==
dependencies:
"@algolia/autocomplete-plugin-algolia-insights" "1.19.8"
"@algolia/autocomplete-shared" "1.19.8"
"@algolia/autocomplete-plugin-algolia-insights@1.19.2":
version "1.19.2"
resolved "https://registry.yarnpkg.com/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.19.2.tgz#3584b625b9317e333d1ae43664d02358e175c52d"
@ -35,23 +27,11 @@
dependencies:
"@algolia/autocomplete-shared" "1.19.2"
"@algolia/autocomplete-plugin-algolia-insights@1.19.8":
version "1.19.8"
resolved "https://registry.yarnpkg.com/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.19.8.tgz#f60d21edbe2a42e6d4e2215430733e3f51641471"
integrity sha512-ZvJWO8ZZJDpc1LNM2TTBdmQsZBLMR4rU5iNR2OYvEeFBiaf/0ESnRSSLQbryarJY4SVxtoz6A2ZtDMNM+iQEAA==
dependencies:
"@algolia/autocomplete-shared" "1.19.8"
"@algolia/autocomplete-shared@1.19.2":
version "1.19.2"
resolved "https://registry.yarnpkg.com/@algolia/autocomplete-shared/-/autocomplete-shared-1.19.2.tgz#c0b7b8dc30a5c65b70501640e62b009535e4578f"
integrity sha512-jEazxZTVD2nLrC+wYlVHQgpBoBB5KPStrJxLzsIFl6Kqd1AlG9sIAGl39V5tECLpIQzB3Qa2T6ZPJ1ChkwMK/w==
"@algolia/autocomplete-shared@1.19.8":
version "1.19.8"
resolved "https://registry.yarnpkg.com/@algolia/autocomplete-shared/-/autocomplete-shared-1.19.8.tgz#5d723d8bdb448efbb1b0e1c7ff94cc18e5b1dc0e"
integrity sha512-h5hf2t8ejF6vlOgvLaZzQbWs5SyH2z4PAWygNAvvD/2RI29hdQ54ldUGwqVuj9Srs+n8XUKTPUqb7fvhBhQrnQ==
"@algolia/client-abtesting@5.49.2":
version "5.49.2"
resolved "https://registry.yarnpkg.com/@algolia/client-abtesting/-/client-abtesting-5.49.2.tgz#0c7f46ba2789e30db53eb31f816aa31fe1ec750e"
@ -1478,44 +1458,24 @@
resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70"
integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==
"@docsearch/core@4.6.2":
version "4.6.2"
resolved "https://registry.yarnpkg.com/@docsearch/core/-/core-4.6.2.tgz#0a6fdc13b1eb12153cb19316f911479b67f7bd58"
integrity sha512-/S0e6Dj7Zcm8m9Rru49YEX49dhU11be68c+S/BCyN8zQsTTgkKzXlhRbVL5mV6lOLC2+ZRRryaTdcm070Ug2oA==
"@docsearch/core@4.6.0":
version "4.6.0"
resolved "https://registry.yarnpkg.com/@docsearch/core/-/core-4.6.0.tgz#223e40f4cf422e8a7ad005b5653a76c0272541ee"
integrity sha512-IqG3oSd529jVRQ4dWZQKwZwQLVd//bWJTz2HiL0LkiHrI4U/vLrBasKB7lwQB/69nBAcCgs3TmudxTZSLH/ZQg==
"@docsearch/css@4.6.2":
version "4.6.2"
resolved "https://registry.yarnpkg.com/@docsearch/css/-/css-4.6.2.tgz#986776619dccbf798176c75e858cc22f5e710bb4"
integrity sha512-fH/cn8BjEEdM2nJdjNMHIvOVYupG6AIDtFVDgIZrNzdCSj4KXr9kd+hsehqsNGYjpUjObeKYKvgy/IwCb1jZYQ==
"@docsearch/css@4.6.0":
version "4.6.0"
resolved "https://registry.yarnpkg.com/@docsearch/css/-/css-4.6.0.tgz#1780de042f61d11d60091f5c2f734543c3bc5d07"
integrity sha512-YlcAimkXclvqta47g47efzCM5CFxDwv2ClkDfEs/fC/Ak0OxPH2b3czwa4o8O1TRBf+ujFF2RiUwszz2fPVNJQ==
"@docsearch/react@^3.9.0 || ^4.3.2":
version "4.6.2"
resolved "https://registry.yarnpkg.com/@docsearch/react/-/react-4.6.2.tgz#e6c65fb87fb943eefaa936debe6d31bb51b25056"
integrity sha512-/BbtGFtqVOGwZx0dw/UfhN/0/DmMQYnulY4iv0tPRhC2JCXv0ka/+izwt3Jzo1ZxXS/2eMvv9zHsBJOK1I9f/w==
"@docsearch/react@^3.9.0 || ^4.1.0":
version "4.6.0"
resolved "https://registry.yarnpkg.com/@docsearch/react/-/react-4.6.0.tgz#b9a85539fda5a5398e0613fff9681d87085c84af"
integrity sha512-j8H5B4ArGxBPBWvw3X0J0Rm/Pjv2JDa2rV5OE0DLTp5oiBCptIJ/YlNOhZxuzbO2nwge+o3Z52nJRi3hryK9cA==
dependencies:
"@algolia/autocomplete-core" "1.19.2"
"@docsearch/core" "4.6.2"
"@docsearch/css" "4.6.2"
"@docusaurus/babel@3.10.0":
version "3.10.0"
resolved "https://registry.yarnpkg.com/@docusaurus/babel/-/babel-3.10.0.tgz#819819f107233dfcf50b59cd51158f23fb04878a"
integrity sha512-mqCJhCZNZUDg0zgDEaPTM4DnRsisa24HdqTy/qn/MQlbwhTb4WVaZg6ZyX6yIVKqTz8fS1hBMgM+98z+BeJJDg==
dependencies:
"@babel/core" "^7.25.9"
"@babel/generator" "^7.25.9"
"@babel/plugin-syntax-dynamic-import" "^7.8.3"
"@babel/plugin-transform-runtime" "^7.25.9"
"@babel/preset-env" "^7.25.9"
"@babel/preset-react" "^7.25.9"
"@babel/preset-typescript" "^7.25.9"
"@babel/runtime" "^7.25.9"
"@babel/traverse" "^7.25.9"
"@docusaurus/logger" "3.10.0"
"@docusaurus/utils" "3.10.0"
babel-plugin-dynamic-import-node "^2.3.3"
fs-extra "^11.1.1"
tslib "^2.6.0"
"@docsearch/core" "4.6.0"
"@docsearch/css" "4.6.0"
"@docusaurus/babel@3.9.2":
version "3.9.2"
@ -1538,36 +1498,6 @@
fs-extra "^11.1.1"
tslib "^2.6.0"
"@docusaurus/bundler@3.10.0":
version "3.10.0"
resolved "https://registry.yarnpkg.com/@docusaurus/bundler/-/bundler-3.10.0.tgz#878c4c46bfa3434671ea37a43da184238a6aae26"
integrity sha512-iONUGZGgp+lAkw/cJZH6irONcF4p8+278IsdRlq8lYhxGjkoNUs0w7F4gVXBYSNChq5KG5/JleTSsdJySShxow==
dependencies:
"@babel/core" "^7.25.9"
"@docusaurus/babel" "3.10.0"
"@docusaurus/cssnano-preset" "3.10.0"
"@docusaurus/logger" "3.10.0"
"@docusaurus/types" "3.10.0"
"@docusaurus/utils" "3.10.0"
babel-loader "^9.2.1"
clean-css "^5.3.3"
copy-webpack-plugin "^11.0.0"
css-loader "^6.11.0"
css-minimizer-webpack-plugin "^5.0.1"
cssnano "^6.1.2"
file-loader "^6.2.0"
html-minifier-terser "^7.2.0"
mini-css-extract-plugin "^2.9.2"
null-loader "^4.0.1"
postcss "^8.5.4"
postcss-loader "^7.3.4"
postcss-preset-env "^10.2.1"
terser-webpack-plugin "^5.3.9"
tslib "^2.6.0"
url-loader "^4.1.1"
webpack "^5.95.0"
webpackbar "^6.0.1"
"@docusaurus/bundler@3.9.2":
version "3.9.2"
resolved "https://registry.yarnpkg.com/@docusaurus/bundler/-/bundler-3.9.2.tgz#0ca82cda4acf13a493e3f66061aea351e9d356cf"
@ -1598,54 +1528,6 @@
webpack "^5.95.0"
webpackbar "^6.0.1"
"@docusaurus/core@3.10.0":
version "3.10.0"
resolved "https://registry.yarnpkg.com/@docusaurus/core/-/core-3.10.0.tgz#642e71a0209d62c3f5ef275ed9d74a881f40df39"
integrity sha512-mgLdQsO8xppnQZc3LPi+Mf+PkPeyxJeIx11AXAq/14fsaMefInQiMEZUUmrc7J+956G/f7MwE7tn8KZgi3iRcA==
dependencies:
"@docusaurus/babel" "3.10.0"
"@docusaurus/bundler" "3.10.0"
"@docusaurus/logger" "3.10.0"
"@docusaurus/mdx-loader" "3.10.0"
"@docusaurus/utils" "3.10.0"
"@docusaurus/utils-common" "3.10.0"
"@docusaurus/utils-validation" "3.10.0"
boxen "^6.2.1"
chalk "^4.1.2"
chokidar "^3.5.3"
cli-table3 "^0.6.3"
combine-promises "^1.1.0"
commander "^5.1.0"
core-js "^3.31.1"
detect-port "^1.5.1"
escape-html "^1.0.3"
eta "^2.2.0"
eval "^0.1.8"
execa "^5.1.1"
fs-extra "^11.1.1"
html-tags "^3.3.1"
html-webpack-plugin "^5.6.0"
leven "^3.1.0"
lodash "^4.17.21"
open "^8.4.0"
p-map "^4.0.0"
prompts "^2.4.2"
react-helmet-async "npm:@slorber/react-helmet-async@1.3.0"
react-loadable "npm:@docusaurus/react-loadable@6.0.0"
react-loadable-ssr-addon-v5-slorber "^1.0.3"
react-router "^5.3.4"
react-router-config "^5.1.1"
react-router-dom "^5.3.4"
semver "^7.5.4"
serve-handler "^6.1.7"
tinypool "^1.0.2"
tslib "^2.6.0"
update-notifier "^6.0.2"
webpack "^5.95.0"
webpack-bundle-analyzer "^4.10.2"
webpack-dev-server "^5.2.2"
webpack-merge "^6.0.1"
"@docusaurus/core@3.9.2":
version "3.9.2"
resolved "https://registry.yarnpkg.com/@docusaurus/core/-/core-3.9.2.tgz#cc970f29b85a8926d63c84f8cffdcda43ed266ff"
@ -1694,16 +1576,6 @@
webpack-dev-server "^5.2.2"
webpack-merge "^6.0.1"
"@docusaurus/cssnano-preset@3.10.0":
version "3.10.0"
resolved "https://registry.yarnpkg.com/@docusaurus/cssnano-preset/-/cssnano-preset-3.10.0.tgz#be1b435c33df09d743473d3fadda67b4568dfae3"
integrity sha512-qzSshTO1DB3TYW+dPUal5KHM7XPc5YQfzF3Kdb2NDACJUyGbNcFtw3tGkCJlYwhNCRKbZcmwraKUS1i5dcHdGg==
dependencies:
cssnano-preset-advanced "^6.1.2"
postcss "^8.5.4"
postcss-sort-media-queries "^5.2.0"
tslib "^2.6.0"
"@docusaurus/cssnano-preset@3.9.2":
version "3.9.2"
resolved "https://registry.yarnpkg.com/@docusaurus/cssnano-preset/-/cssnano-preset-3.9.2.tgz#523aab65349db3c51a77f2489048d28527759428"
@ -1714,14 +1586,6 @@
postcss-sort-media-queries "^5.2.0"
tslib "^2.6.0"
"@docusaurus/logger@3.10.0":
version "3.10.0"
resolved "https://registry.yarnpkg.com/@docusaurus/logger/-/logger-3.10.0.tgz#2bacbd004dd78e3da926dbe8f6fa9a930856575d"
integrity sha512-9jrZzFuBH1LDRlZ7cznAhCLmAZ3HSDqgwdrSSZdGHq9SPUOQgXXu8mnxe2ZRB9NS1PCpMTIOVUqDtZPIhMafZg==
dependencies:
chalk "^4.1.2"
tslib "^2.6.0"
"@docusaurus/logger@3.9.2":
version "3.9.2"
resolved "https://registry.yarnpkg.com/@docusaurus/logger/-/logger-3.9.2.tgz#6ec6364b90f5a618a438cc9fd01ac7376869f92a"
@ -1730,36 +1594,6 @@
chalk "^4.1.2"
tslib "^2.6.0"
"@docusaurus/mdx-loader@3.10.0":
version "3.10.0"
resolved "https://registry.yarnpkg.com/@docusaurus/mdx-loader/-/mdx-loader-3.10.0.tgz#1d4b050d751389ecf38dee48bcb61e53df8ffb82"
integrity sha512-mQQV97080AH4PYNs087l202NMDqRopZA4mg5W76ZZyTFrmWhJ3mHg+8A+drJVENxw5/Q+wHMHLgsx+9z1nEs0A==
dependencies:
"@docusaurus/logger" "3.10.0"
"@docusaurus/utils" "3.10.0"
"@docusaurus/utils-validation" "3.10.0"
"@mdx-js/mdx" "^3.0.0"
"@slorber/remark-comment" "^1.0.0"
escape-html "^1.0.3"
estree-util-value-to-estree "^3.0.1"
file-loader "^6.2.0"
fs-extra "^11.1.1"
image-size "^2.0.2"
mdast-util-mdx "^3.0.0"
mdast-util-to-string "^4.0.0"
rehype-raw "^7.0.0"
remark-directive "^3.0.0"
remark-emoji "^4.0.0"
remark-frontmatter "^5.0.0"
remark-gfm "^4.0.0"
stringify-object "^3.3.0"
tslib "^2.6.0"
unified "^11.0.3"
unist-util-visit "^5.0.0"
url-loader "^4.1.1"
vfile "^6.0.1"
webpack "^5.88.1"
"@docusaurus/mdx-loader@3.9.2":
version "3.9.2"
resolved "https://registry.yarnpkg.com/@docusaurus/mdx-loader/-/mdx-loader-3.9.2.tgz#78d238de6c6203fa811cc2a7e90b9b79e111408c"
@ -1790,19 +1624,6 @@
vfile "^6.0.1"
webpack "^5.88.1"
"@docusaurus/module-type-aliases@3.10.0":
version "3.10.0"
resolved "https://registry.yarnpkg.com/@docusaurus/module-type-aliases/-/module-type-aliases-3.10.0.tgz#749928f104d563f11f046bf0c9ab6489a470c7c8"
integrity sha512-/1O0Zg8w3DFrYX/I6Fbss7OJrtZw1QoyjDhegiFNHVi9A9Y0gQ3jUAytVxF6ywpAWpLyLxch8nN8H/V3XfzdJQ==
dependencies:
"@docusaurus/types" "3.10.0"
"@types/history" "^4.7.11"
"@types/react" "*"
"@types/react-router-config" "*"
"@types/react-router-dom" "*"
react-helmet-async "npm:@slorber/react-helmet-async@1.3.0"
react-loadable "npm:@docusaurus/react-loadable@6.0.0"
"@docusaurus/module-type-aliases@3.9.2":
version "3.9.2"
resolved "https://registry.yarnpkg.com/@docusaurus/module-type-aliases/-/module-type-aliases-3.9.2.tgz#993c7cb0114363dea5ef6855e989b3ad4b843a34"
@ -1816,21 +1637,20 @@
react-helmet-async "npm:@slorber/react-helmet-async@1.3.0"
react-loadable "npm:@docusaurus/react-loadable@6.0.0"
"@docusaurus/plugin-content-blog@3.10.0":
version "3.10.0"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.10.0.tgz#10095291b637440847854ecb2c8afcd8746debd7"
integrity sha512-RuTz68DhB7CL96QO5UsFbciD7GPYq6QV+YMfF9V0+N4ZgLhJIBgpVAr8GobrKF6NRe5cyWWETU5z5T834piG9g==
"@docusaurus/plugin-content-blog@3.9.2":
version "3.9.2"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-blog/-/plugin-content-blog-3.9.2.tgz#d5ce51eb7757bdab0515e2dd26a793ed4e119df9"
integrity sha512-3I2HXy3L1QcjLJLGAoTvoBnpOwa6DPUa3Q0dMK19UTY9mhPkKQg/DYhAGTiBUKcTR0f08iw7kLPqOhIgdV3eVQ==
dependencies:
"@docusaurus/core" "3.10.0"
"@docusaurus/logger" "3.10.0"
"@docusaurus/mdx-loader" "3.10.0"
"@docusaurus/theme-common" "3.10.0"
"@docusaurus/types" "3.10.0"
"@docusaurus/utils" "3.10.0"
"@docusaurus/utils-common" "3.10.0"
"@docusaurus/utils-validation" "3.10.0"
"@docusaurus/core" "3.9.2"
"@docusaurus/logger" "3.9.2"
"@docusaurus/mdx-loader" "3.9.2"
"@docusaurus/theme-common" "3.9.2"
"@docusaurus/types" "3.9.2"
"@docusaurus/utils" "3.9.2"
"@docusaurus/utils-common" "3.9.2"
"@docusaurus/utils-validation" "3.9.2"
cheerio "1.0.0-rc.12"
combine-promises "^1.1.0"
feed "^4.2.2"
fs-extra "^11.1.1"
lodash "^4.17.21"
@ -1841,31 +1661,7 @@
utility-types "^3.10.0"
webpack "^5.88.1"
"@docusaurus/plugin-content-docs@3.10.0":
version "3.10.0"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.10.0.tgz#9c4ea1d5a405340f28c281d2e4586c695a7c65a5"
integrity sha512-9BjHhf15ct8Z7TThTC0xRndKDVvMKmVsAGAN7W9FpNRzfMdScOGcXtLmcCWtJGvAezjOJIm6CxOYCy3Io5+RnQ==
dependencies:
"@docusaurus/core" "3.10.0"
"@docusaurus/logger" "3.10.0"
"@docusaurus/mdx-loader" "3.10.0"
"@docusaurus/module-type-aliases" "3.10.0"
"@docusaurus/theme-common" "3.10.0"
"@docusaurus/types" "3.10.0"
"@docusaurus/utils" "3.10.0"
"@docusaurus/utils-common" "3.10.0"
"@docusaurus/utils-validation" "3.10.0"
"@types/react-router-config" "^5.0.7"
combine-promises "^1.1.0"
fs-extra "^11.1.1"
js-yaml "^4.1.0"
lodash "^4.17.21"
schema-dts "^1.1.2"
tslib "^2.6.0"
utility-types "^3.10.0"
webpack "^5.88.1"
"@docusaurus/plugin-content-docs@^2 || ^3":
"@docusaurus/plugin-content-docs@3.9.2", "@docusaurus/plugin-content-docs@^2 || ^3":
version "3.9.2"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-docs/-/plugin-content-docs-3.9.2.tgz#cd8f2d1c06e53c3fa3d24bdfcb48d237bf2d6b2e"
integrity sha512-C5wZsGuKTY8jEYsqdxhhFOe1ZDjH0uIYJ9T/jebHwkyxqnr4wW0jTkB72OMqNjsoQRcb0JN3PcSeTwFlVgzCZg==
@ -1889,145 +1685,144 @@
utility-types "^3.10.0"
webpack "^5.88.1"
"@docusaurus/plugin-content-pages@3.10.0":
version "3.10.0"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.10.0.tgz#7670cbb3c849f434949f542bfdfded1580a13165"
integrity sha512-5amX8kEJI+nIGtuLVjYk59Y5utEJ3CHETFOPEE4cooIRLA4xM4iBsA6zFgu4ljcopeYwvBzFEWf5g2I6Yb9SkA==
"@docusaurus/plugin-content-pages@3.9.2":
version "3.9.2"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-content-pages/-/plugin-content-pages-3.9.2.tgz#22db6c88ade91cec0a9e87a00b8089898051b08d"
integrity sha512-s4849w/p4noXUrGpPUF0BPqIAfdAe76BLaRGAGKZ1gTDNiGxGcpsLcwJ9OTi1/V8A+AzvsmI9pkjie2zjIQZKA==
dependencies:
"@docusaurus/core" "3.10.0"
"@docusaurus/mdx-loader" "3.10.0"
"@docusaurus/types" "3.10.0"
"@docusaurus/utils" "3.10.0"
"@docusaurus/utils-validation" "3.10.0"
"@docusaurus/core" "3.9.2"
"@docusaurus/mdx-loader" "3.9.2"
"@docusaurus/types" "3.9.2"
"@docusaurus/utils" "3.9.2"
"@docusaurus/utils-validation" "3.9.2"
fs-extra "^11.1.1"
tslib "^2.6.0"
webpack "^5.88.1"
"@docusaurus/plugin-css-cascade-layers@3.10.0":
version "3.10.0"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-css-cascade-layers/-/plugin-css-cascade-layers-3.10.0.tgz#71e318d842be95f92be6c3dca00ceea4971d0edb"
integrity sha512-6q1vtt5FJcg5osgkHeM1euErECNqEZ5Z1j69yiNx2luEBIso+nxCkS9nqj8w+MK5X7rvKEToGhFfOFWncs51pQ==
"@docusaurus/plugin-css-cascade-layers@3.9.2":
version "3.9.2"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-css-cascade-layers/-/plugin-css-cascade-layers-3.9.2.tgz#358c85f63f1c6a11f611f1b8889d9435c11b22f8"
integrity sha512-w1s3+Ss+eOQbscGM4cfIFBlVg/QKxyYgj26k5AnakuHkKxH6004ZtuLe5awMBotIYF2bbGDoDhpgQ4r/kcj4rQ==
dependencies:
"@docusaurus/core" "3.10.0"
"@docusaurus/types" "3.10.0"
"@docusaurus/utils" "3.10.0"
"@docusaurus/utils-validation" "3.10.0"
"@docusaurus/core" "3.9.2"
"@docusaurus/types" "3.9.2"
"@docusaurus/utils" "3.9.2"
"@docusaurus/utils-validation" "3.9.2"
tslib "^2.6.0"
"@docusaurus/plugin-debug@3.10.0":
version "3.10.0"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-debug/-/plugin-debug-3.10.0.tgz#e77f924604e1e09d5d90fe0bdf23a3be8ea3307e"
integrity sha512-XcljKN+G+nmmK69uQA1d9BlYU3ZftG3T3zpK8/7Hf/wrOlV7TA4Ampdrdwkg0jElKdKAoSnPhCO0/U3bQGsVQQ==
"@docusaurus/plugin-debug@3.9.2":
version "3.9.2"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-debug/-/plugin-debug-3.9.2.tgz#b5df4db115583f5404a252dbf66f379ff933e53c"
integrity sha512-j7a5hWuAFxyQAkilZwhsQ/b3T7FfHZ+0dub6j/GxKNFJp2h9qk/P1Bp7vrGASnvA9KNQBBL1ZXTe7jlh4VdPdA==
dependencies:
"@docusaurus/core" "3.10.0"
"@docusaurus/types" "3.10.0"
"@docusaurus/utils" "3.10.0"
"@docusaurus/core" "3.9.2"
"@docusaurus/types" "3.9.2"
"@docusaurus/utils" "3.9.2"
fs-extra "^11.1.1"
react-json-view-lite "^2.3.0"
tslib "^2.6.0"
"@docusaurus/plugin-google-analytics@3.10.0":
version "3.10.0"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.10.0.tgz#22c7e976fe4d970c7cd1c73c9723d9a5786c6e37"
integrity sha512-hTEoodatpBZnUat5nFExbuTGA1lhWGy7vZGuTew5Q3QDtGKFpSJLYmZJhdTjvCFwv1+qQ67hgAVlKdJOB8TXow==
"@docusaurus/plugin-google-analytics@3.9.2":
version "3.9.2"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-3.9.2.tgz#857fe075fdeccdf6959e62954d9efe39769fa247"
integrity sha512-mAwwQJ1Us9jL/lVjXtErXto4p4/iaLlweC54yDUK1a97WfkC6Z2k5/769JsFgwOwOP+n5mUQGACXOEQ0XDuVUw==
dependencies:
"@docusaurus/core" "3.10.0"
"@docusaurus/types" "3.10.0"
"@docusaurus/utils-validation" "3.10.0"
"@docusaurus/core" "3.9.2"
"@docusaurus/types" "3.9.2"
"@docusaurus/utils-validation" "3.9.2"
tslib "^2.6.0"
"@docusaurus/plugin-google-gtag@3.10.0":
version "3.10.0"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.10.0.tgz#c38a2ba638257851cc845b934506b80c08d47f96"
integrity sha512-iB/Zzjv/eelJRbdULZqzWCbgMgJ7ht4ONVjXtN3+BI/muil6S87gQ1OJyPwlXD+ELdKkitC7bWv5eJdYOZLhrQ==
"@docusaurus/plugin-google-gtag@3.9.2":
version "3.9.2"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-3.9.2.tgz#df75b1a90ae9266b0471909ba0265f46d5dcae62"
integrity sha512-YJ4lDCphabBtw19ooSlc1MnxtYGpjFV9rEdzjLsUnBCeis2djUyCozZaFhCg6NGEwOn7HDDyMh0yzcdRpnuIvA==
dependencies:
"@docusaurus/core" "3.10.0"
"@docusaurus/types" "3.10.0"
"@docusaurus/utils-validation" "3.10.0"
"@types/gtag.js" "^0.0.20"
"@docusaurus/core" "3.9.2"
"@docusaurus/types" "3.9.2"
"@docusaurus/utils-validation" "3.9.2"
"@types/gtag.js" "^0.0.12"
tslib "^2.6.0"
"@docusaurus/plugin-google-tag-manager@3.10.0":
version "3.10.0"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.10.0.tgz#5469c923cc1ad4608399d0b17e5fcacd8e030d56"
integrity sha512-FEjZxqKgLHa+Wez/EgKxRwvArNCWIScfyEQD95rot7jkxp6nonjI5XIbGfO/iYhM5Qinwe8aIEQHP2KZtpqVuA==
"@docusaurus/plugin-google-tag-manager@3.9.2":
version "3.9.2"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-google-tag-manager/-/plugin-google-tag-manager-3.9.2.tgz#d1a3cf935acb7d31b84685e92d70a1d342946677"
integrity sha512-LJtIrkZN/tuHD8NqDAW1Tnw0ekOwRTfobWPsdO15YxcicBo2ykKF0/D6n0vVBfd3srwr9Z6rzrIWYrMzBGrvNw==
dependencies:
"@docusaurus/core" "3.10.0"
"@docusaurus/types" "3.10.0"
"@docusaurus/utils-validation" "3.10.0"
"@docusaurus/core" "3.9.2"
"@docusaurus/types" "3.9.2"
"@docusaurus/utils-validation" "3.9.2"
tslib "^2.6.0"
"@docusaurus/plugin-sitemap@3.10.0":
version "3.10.0"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.10.0.tgz#35d59d46803f279f22aa64fc1bd18c048f12662b"
integrity sha512-DVTSLjB97hIjmayGnGcBfognCeI7ZuUKgEnU7Oz81JYqXtVg94mVTthDjq3QHTylYNeCUbkaW8VF0FDLcc8pPw==
"@docusaurus/plugin-sitemap@3.9.2":
version "3.9.2"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-sitemap/-/plugin-sitemap-3.9.2.tgz#e1d9f7012942562cc0c6543d3cb2cdc4ae713dc4"
integrity sha512-WLh7ymgDXjG8oPoM/T4/zUP7KcSuFYRZAUTl8vR6VzYkfc18GBM4xLhcT+AKOwun6kBivYKUJf+vlqYJkm+RHw==
dependencies:
"@docusaurus/core" "3.10.0"
"@docusaurus/logger" "3.10.0"
"@docusaurus/types" "3.10.0"
"@docusaurus/utils" "3.10.0"
"@docusaurus/utils-common" "3.10.0"
"@docusaurus/utils-validation" "3.10.0"
"@docusaurus/core" "3.9.2"
"@docusaurus/logger" "3.9.2"
"@docusaurus/types" "3.9.2"
"@docusaurus/utils" "3.9.2"
"@docusaurus/utils-common" "3.9.2"
"@docusaurus/utils-validation" "3.9.2"
fs-extra "^11.1.1"
sitemap "^7.1.1"
tslib "^2.6.0"
"@docusaurus/plugin-svgr@3.10.0":
version "3.10.0"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-svgr/-/plugin-svgr-3.10.0.tgz#8ada2e6dd8318d20206a9b044fc091a5794ba3f0"
integrity sha512-lNljBESaETZqVBMPqkrGchr+UPT1eZzEPLmJhz8I76BxbjqgsUnRvrq6lQJ9sYjgmgX52KB7kkgczqd2yzoswQ==
"@docusaurus/plugin-svgr@3.9.2":
version "3.9.2"
resolved "https://registry.yarnpkg.com/@docusaurus/plugin-svgr/-/plugin-svgr-3.9.2.tgz#62857ed79d97c0150d25f7e7380fdee65671163a"
integrity sha512-n+1DE+5b3Lnf27TgVU5jM1d4x5tUh2oW5LTsBxJX4PsAPV0JGcmI6p3yLYtEY0LRVEIJh+8RsdQmRE66wSV8mw==
dependencies:
"@docusaurus/core" "3.10.0"
"@docusaurus/types" "3.10.0"
"@docusaurus/utils" "3.10.0"
"@docusaurus/utils-validation" "3.10.0"
"@docusaurus/core" "3.9.2"
"@docusaurus/types" "3.9.2"
"@docusaurus/utils" "3.9.2"
"@docusaurus/utils-validation" "3.9.2"
"@svgr/core" "8.1.0"
"@svgr/webpack" "^8.1.0"
tslib "^2.6.0"
webpack "^5.88.1"
"@docusaurus/preset-classic@3.10.0":
version "3.10.0"
resolved "https://registry.yarnpkg.com/@docusaurus/preset-classic/-/preset-classic-3.10.0.tgz#74b6facdaf568bcd41ec90cae9aebb7ca0ac8619"
integrity sha512-kw/Ye02Hc6xP1OdTswy8yxQEHg0fdPpyWAQRxr5b2x3h7LlG2Zgbb5BDFROnXDDMpUxB7YejlocJIE5HIEfpNA==
"@docusaurus/preset-classic@3.9.2":
version "3.9.2"
resolved "https://registry.yarnpkg.com/@docusaurus/preset-classic/-/preset-classic-3.9.2.tgz#85cc4f91baf177f8146c9ce896dfa1f0fd377050"
integrity sha512-IgyYO2Gvaigi21LuDIe+nvmN/dfGXAiMcV/murFqcpjnZc7jxFAxW+9LEjdPt61uZLxG4ByW/oUmX/DDK9t/8w==
dependencies:
"@docusaurus/core" "3.10.0"
"@docusaurus/plugin-content-blog" "3.10.0"
"@docusaurus/plugin-content-docs" "3.10.0"
"@docusaurus/plugin-content-pages" "3.10.0"
"@docusaurus/plugin-css-cascade-layers" "3.10.0"
"@docusaurus/plugin-debug" "3.10.0"
"@docusaurus/plugin-google-analytics" "3.10.0"
"@docusaurus/plugin-google-gtag" "3.10.0"
"@docusaurus/plugin-google-tag-manager" "3.10.0"
"@docusaurus/plugin-sitemap" "3.10.0"
"@docusaurus/plugin-svgr" "3.10.0"
"@docusaurus/theme-classic" "3.10.0"
"@docusaurus/theme-common" "3.10.0"
"@docusaurus/theme-search-algolia" "3.10.0"
"@docusaurus/types" "3.10.0"
"@docusaurus/core" "3.9.2"
"@docusaurus/plugin-content-blog" "3.9.2"
"@docusaurus/plugin-content-docs" "3.9.2"
"@docusaurus/plugin-content-pages" "3.9.2"
"@docusaurus/plugin-css-cascade-layers" "3.9.2"
"@docusaurus/plugin-debug" "3.9.2"
"@docusaurus/plugin-google-analytics" "3.9.2"
"@docusaurus/plugin-google-gtag" "3.9.2"
"@docusaurus/plugin-google-tag-manager" "3.9.2"
"@docusaurus/plugin-sitemap" "3.9.2"
"@docusaurus/plugin-svgr" "3.9.2"
"@docusaurus/theme-classic" "3.9.2"
"@docusaurus/theme-common" "3.9.2"
"@docusaurus/theme-search-algolia" "3.9.2"
"@docusaurus/types" "3.9.2"
"@docusaurus/theme-classic@3.10.0":
version "3.10.0"
resolved "https://registry.yarnpkg.com/@docusaurus/theme-classic/-/theme-classic-3.10.0.tgz#d937915c691189f27ced649c822994d839ea565b"
integrity sha512-9msCAsRdN+UG+RwPwCFb0uKy4tGoPh5YfBozXeGUtIeAgsMdn6f3G/oY861luZ3t8S2ET8S9Y/1GnpJAGWytww==
"@docusaurus/theme-classic@3.9.2":
version "3.9.2"
resolved "https://registry.yarnpkg.com/@docusaurus/theme-classic/-/theme-classic-3.9.2.tgz#6e514f99a0ff42b80afcf42d5e5d042618311ce0"
integrity sha512-IGUsArG5hhekXd7RDb11v94ycpJpFdJPkLnt10fFQWOVxAtq5/D7hT6lzc2fhyQKaaCE62qVajOMKL7OiAFAIA==
dependencies:
"@docusaurus/core" "3.10.0"
"@docusaurus/logger" "3.10.0"
"@docusaurus/mdx-loader" "3.10.0"
"@docusaurus/module-type-aliases" "3.10.0"
"@docusaurus/plugin-content-blog" "3.10.0"
"@docusaurus/plugin-content-docs" "3.10.0"
"@docusaurus/plugin-content-pages" "3.10.0"
"@docusaurus/theme-common" "3.10.0"
"@docusaurus/theme-translations" "3.10.0"
"@docusaurus/types" "3.10.0"
"@docusaurus/utils" "3.10.0"
"@docusaurus/utils-common" "3.10.0"
"@docusaurus/utils-validation" "3.10.0"
"@docusaurus/core" "3.9.2"
"@docusaurus/logger" "3.9.2"
"@docusaurus/mdx-loader" "3.9.2"
"@docusaurus/module-type-aliases" "3.9.2"
"@docusaurus/plugin-content-blog" "3.9.2"
"@docusaurus/plugin-content-docs" "3.9.2"
"@docusaurus/plugin-content-pages" "3.9.2"
"@docusaurus/theme-common" "3.9.2"
"@docusaurus/theme-translations" "3.9.2"
"@docusaurus/types" "3.9.2"
"@docusaurus/utils" "3.9.2"
"@docusaurus/utils-common" "3.9.2"
"@docusaurus/utils-validation" "3.9.2"
"@mdx-js/react" "^3.0.0"
clsx "^2.0.0"
copy-text-to-clipboard "^3.2.0"
infima "0.2.0-alpha.45"
lodash "^4.17.21"
nprogress "^0.2.0"
@ -2039,24 +1834,6 @@
tslib "^2.6.0"
utility-types "^3.10.0"
"@docusaurus/theme-common@3.10.0":
version "3.10.0"
resolved "https://registry.yarnpkg.com/@docusaurus/theme-common/-/theme-common-3.10.0.tgz#70b419ccfdf62f092299354a72d1692e81be597d"
integrity sha512-Dkp1YXKn16ByCJAdIjbDIOpVb4Z66MsVD694/ilX1vAAHaVEMrVsf/NPd9VgreyFx08rJ9GqV1MtzsbTcU73Kg==
dependencies:
"@docusaurus/mdx-loader" "3.10.0"
"@docusaurus/module-type-aliases" "3.10.0"
"@docusaurus/utils" "3.10.0"
"@docusaurus/utils-common" "3.10.0"
"@types/history" "^4.7.11"
"@types/react" "*"
"@types/react-router-config" "*"
clsx "^2.0.0"
parse-numeric-range "^1.3.0"
prism-react-renderer "^2.3.0"
tslib "^2.6.0"
utility-types "^3.10.0"
"@docusaurus/theme-common@3.9.2":
version "3.9.2"
resolved "https://registry.yarnpkg.com/@docusaurus/theme-common/-/theme-common-3.9.2.tgz#487172c6fef9815c2746ef62a71e4f5b326f9ba5"
@ -2075,20 +1852,19 @@
tslib "^2.6.0"
utility-types "^3.10.0"
"@docusaurus/theme-search-algolia@3.10.0":
version "3.10.0"
resolved "https://registry.yarnpkg.com/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.10.0.tgz#0ff57fe58db6abde8f5ad2877e459cd2fa6e7464"
integrity sha512-f5FPKI08e3JRG63vR/o4qeuUVHUHzFzM0nnF+AkB67soAZgNsKJRf2qmUZvlQkGwlV+QFkKe4D0ANMh1jToU3g==
"@docusaurus/theme-search-algolia@3.9.2":
version "3.9.2"
resolved "https://registry.yarnpkg.com/@docusaurus/theme-search-algolia/-/theme-search-algolia-3.9.2.tgz#420fd5b27fc1673b48151fdc9fe7167ba135ed50"
integrity sha512-GBDSFNwjnh5/LdkxCKQHkgO2pIMX1447BxYUBG2wBiajS21uj64a+gH/qlbQjDLxmGrbrllBrtJkUHxIsiwRnw==
dependencies:
"@algolia/autocomplete-core" "^1.19.2"
"@docsearch/react" "^3.9.0 || ^4.3.2"
"@docusaurus/core" "3.10.0"
"@docusaurus/logger" "3.10.0"
"@docusaurus/plugin-content-docs" "3.10.0"
"@docusaurus/theme-common" "3.10.0"
"@docusaurus/theme-translations" "3.10.0"
"@docusaurus/utils" "3.10.0"
"@docusaurus/utils-validation" "3.10.0"
"@docsearch/react" "^3.9.0 || ^4.1.0"
"@docusaurus/core" "3.9.2"
"@docusaurus/logger" "3.9.2"
"@docusaurus/plugin-content-docs" "3.9.2"
"@docusaurus/theme-common" "3.9.2"
"@docusaurus/theme-translations" "3.9.2"
"@docusaurus/utils" "3.9.2"
"@docusaurus/utils-validation" "3.9.2"
algoliasearch "^5.37.0"
algoliasearch-helper "^3.26.0"
clsx "^2.0.0"
@ -2098,15 +1874,7 @@
tslib "^2.6.0"
utility-types "^3.10.0"
"@docusaurus/theme-translations@3.10.0":
version "3.10.0"
resolved "https://registry.yarnpkg.com/@docusaurus/theme-translations/-/theme-translations-3.10.0.tgz#8fdc23d29bd7f907db49c36cf65e2123d96be300"
integrity sha512-L9IbFLwTc5+XdgH45iQYufLn0SVZd6BUNelDbKIFlH+E4hhjuj/XHWAFMX/w2K59rfy8wak9McOaei7BSUfRPA==
dependencies:
fs-extra "^11.1.1"
tslib "^2.6.0"
"@docusaurus/theme-translations@^2 || ^3":
"@docusaurus/theme-translations@3.9.2", "@docusaurus/theme-translations@^2 || ^3":
version "3.9.2"
resolved "https://registry.yarnpkg.com/@docusaurus/theme-translations/-/theme-translations-3.9.2.tgz#238cd69c2da92d612be3d3b4f95944c1d0f1e041"
integrity sha512-vIryvpP18ON9T9rjgMRFLr2xJVDpw1rtagEGf8Ccce4CkTrvM/fRB8N2nyWYOW5u3DdjkwKw5fBa+3tbn9P4PA==
@ -2114,26 +1882,10 @@
fs-extra "^11.1.1"
tslib "^2.6.0"
"@docusaurus/tsconfig@3.10.0":
version "3.10.0"
resolved "https://registry.yarnpkg.com/@docusaurus/tsconfig/-/tsconfig-3.10.0.tgz#f40a57248828f0503a5f355cf30aa59941c9baaa"
integrity sha512-TXdC3WXuPrdQAexLvjUJfnYf3YKEgEqAs5nK0Q88pRBCW7t7oN4ILvWYb3A5Z1wlSXyXGWW/mCUmLEhdWsjnDQ==
"@docusaurus/types@3.10.0":
version "3.10.0"
resolved "https://registry.yarnpkg.com/@docusaurus/types/-/types-3.10.0.tgz#a69232bba74b738fcf4671fd5f0f079366dd3d13"
integrity sha512-F0dOt3FOoO20rRaFK7whGFQZ3ggyrWEdQc/c8/UiRuzhtg4y1w9FspXH5zpCT07uMnJKBPGh+qNazbNlCQqvSw==
dependencies:
"@mdx-js/mdx" "^3.0.0"
"@types/history" "^4.7.11"
"@types/mdast" "^4.0.2"
"@types/react" "*"
commander "^5.1.0"
joi "^17.9.2"
react-helmet-async "npm:@slorber/react-helmet-async@1.3.0"
utility-types "^3.10.0"
webpack "^5.95.0"
webpack-merge "^5.9.0"
"@docusaurus/tsconfig@3.9.2":
version "3.9.2"
resolved "https://registry.yarnpkg.com/@docusaurus/tsconfig/-/tsconfig-3.9.2.tgz#7f440e0ae665b841e1d487749037f26a0275f9c1"
integrity sha512-j6/Fp4Rlpxsc632cnRnl5HpOWeb6ZKssDj6/XzzAzVGXXfm9Eptx3rxCC+fDzySn9fHTS+CWJjPineCR1bB5WQ==
"@docusaurus/types@3.9.2":
version "3.9.2"
@ -2151,14 +1903,6 @@
webpack "^5.95.0"
webpack-merge "^5.9.0"
"@docusaurus/utils-common@3.10.0":
version "3.10.0"
resolved "https://registry.yarnpkg.com/@docusaurus/utils-common/-/utils-common-3.10.0.tgz#2a6dc76b312664fca7234d33607c085318ff1ae3"
integrity sha512-JyL7sb9QVDgYvudIS81Dv0lsWm7le0vGZSDwsztxWam1SPBqrnkvBy9UYL/amh6pbybkyYTd3CMTkO24oMlCSw==
dependencies:
"@docusaurus/types" "3.10.0"
tslib "^2.6.0"
"@docusaurus/utils-common@3.9.2", "@docusaurus/utils-common@^2 || ^3":
version "3.9.2"
resolved "https://registry.yarnpkg.com/@docusaurus/utils-common/-/utils-common-3.9.2.tgz#e89bfcf43d66359f43df45293fcdf22814847460"
@ -2167,20 +1911,6 @@
"@docusaurus/types" "3.9.2"
tslib "^2.6.0"
"@docusaurus/utils-validation@3.10.0":
version "3.10.0"
resolved "https://registry.yarnpkg.com/@docusaurus/utils-validation/-/utils-validation-3.10.0.tgz#a2418d7f31980d991fd3a1f39c8aad8820b36812"
integrity sha512-c+6n2+ZPOJtWWc8Bb/EYdpSDfjYEScdCu9fB/SNjOmSCf1IdVnGf2T53o0tsz0gDRtCL90tifTL0JE/oMuP1Mw==
dependencies:
"@docusaurus/logger" "3.10.0"
"@docusaurus/utils" "3.10.0"
"@docusaurus/utils-common" "3.10.0"
fs-extra "^11.2.0"
joi "^17.9.2"
js-yaml "^4.1.0"
lodash "^4.17.21"
tslib "^2.6.0"
"@docusaurus/utils-validation@3.9.2", "@docusaurus/utils-validation@^2 || ^3":
version "3.9.2"
resolved "https://registry.yarnpkg.com/@docusaurus/utils-validation/-/utils-validation-3.9.2.tgz#04aec285604790806e2fc5aa90aa950dc7ba75ae"
@ -2195,33 +1925,6 @@
lodash "^4.17.21"
tslib "^2.6.0"
"@docusaurus/utils@3.10.0":
version "3.10.0"
resolved "https://registry.yarnpkg.com/@docusaurus/utils/-/utils-3.10.0.tgz#ea7d7b0d325b60f728decc00bb3908d00ef86faf"
integrity sha512-T3B0WTigsIthe0D4LQa2k+7bJY+c3WS+Wq2JhcznOSpn1lSN64yNtHQXboCj3QnUs1EuAZszQG1SHKu5w5ZrlA==
dependencies:
"@docusaurus/logger" "3.10.0"
"@docusaurus/types" "3.10.0"
"@docusaurus/utils-common" "3.10.0"
escape-string-regexp "^4.0.0"
execa "^5.1.1"
file-loader "^6.2.0"
fs-extra "^11.1.1"
github-slugger "^1.5.0"
globby "^11.1.0"
gray-matter "^4.0.3"
jiti "^1.20.0"
js-yaml "^4.1.0"
lodash "^4.17.21"
micromatch "^4.0.5"
p-queue "^6.6.2"
prompts "^2.4.2"
resolve-pathname "^3.0.0"
tslib "^2.6.0"
url-loader "^4.1.1"
utility-types "^3.10.0"
webpack "^5.88.1"
"@docusaurus/utils@3.9.2", "@docusaurus/utils@^2 || ^3":
version "3.9.2"
resolved "https://registry.yarnpkg.com/@docusaurus/utils/-/utils-3.9.2.tgz#ffab7922631c7e0febcb54e6d499f648bf8a89eb"
@ -3119,10 +2822,10 @@
"@types/qs" "*"
"@types/serve-static" "^1"
"@types/gtag.js@^0.0.20":
version "0.0.20"
resolved "https://registry.yarnpkg.com/@types/gtag.js/-/gtag.js-0.0.20.tgz#e47edabb4ed5ecac90a079275958e6c929d7c08a"
integrity sha512-wwAbk3SA2QeU67unN7zPxjEHmPmlXwZXZvQEpbEUQuMCRGgKyE1m6XDuTUA9b6pCGb/GqJmdfMOY5LuDjJSbbg==
"@types/gtag.js@^0.0.12":
version "0.0.12"
resolved "https://registry.yarnpkg.com/@types/gtag.js/-/gtag.js-0.0.12.tgz#095122edca896689bdfcdd73b057e23064d23572"
integrity sha512-YQV9bUsemkzG81Ea295/nF/5GijnD2Af7QhEofh7xu+kvCN6RdodgNwwGWXB5GMI3NoyvQo0odNctoH/qLMIpg==
"@types/hast@^3.0.0":
version "3.0.4"
@ -4276,11 +3979,6 @@ cookie@~0.7.1:
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.2.tgz#556369c472a2ba910f2979891b526b3436237ed7"
integrity sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==
copy-text-to-clipboard@^3.2.0:
version "3.2.2"
resolved "https://registry.yarnpkg.com/copy-text-to-clipboard/-/copy-text-to-clipboard-3.2.2.tgz#99bc79db3f2d355ec33a08d573aff6804491ddb9"
integrity sha512-T6SqyLd1iLuqPA90J5N4cTalrtovCySh58iiZDGJ6FGznbclKh4UI+FGacQSgFzwKG77W7XT5gwbVEbd9cIH1A==
copy-webpack-plugin@^11.0.0:
version "11.0.0"
resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz#96d4dbdb5f73d02dd72d0528d1958721ab72e04a"
@ -5038,7 +4736,7 @@ events@^3.2.0:
resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400"
integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==
execa@5.1.1, execa@^5.1.1:
execa@5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd"
integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==
@ -8200,9 +7898,9 @@ rc@1.2.8:
strip-json-comments "~2.0.1"
react-dom@^19.0.0:
version "19.2.5"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.2.5.tgz#b8768b10837d0b8e9ca5b9e2d58dff3d880ea25e"
integrity sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==
version "19.2.4"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.2.4.tgz#6fac6bd96f7db477d966c7ec17c1a2b1ad8e6591"
integrity sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==
dependencies:
scheduler "^0.27.0"
@ -8239,13 +7937,6 @@ react-loadable-ssr-addon-v5-slorber@^1.0.1:
dependencies:
"@babel/runtime" "^7.10.3"
react-loadable-ssr-addon-v5-slorber@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/react-loadable-ssr-addon-v5-slorber/-/react-loadable-ssr-addon-v5-slorber-1.0.3.tgz#bb3791bf481222c63a5bc6b96ee23f68cb5614b9"
integrity sha512-GXfh9VLwB5ERaCsU6RULh7tkemeX15aNh6wuMEBtfdyMa7fFG8TXrhXlx1SoEK2Ty/l6XIkzzYIQmyaWW3JgdQ==
dependencies:
"@babel/runtime" "^7.10.3"
"react-loadable@npm:@docusaurus/react-loadable@6.0.0":
version "6.0.0"
resolved "https://registry.yarnpkg.com/@docusaurus/react-loadable/-/react-loadable-6.0.0.tgz#de6c7f73c96542bd70786b8e522d535d69069dc4"
@ -8289,9 +7980,9 @@ react-router@5.3.4, react-router@^5.3.4:
tiny-warning "^1.0.0"
react@^19.0.0:
version "19.2.5"
resolved "https://registry.yarnpkg.com/react/-/react-19.2.5.tgz#c888ab8b8ef33e2597fae8bdb2d77edbdb42858b"
integrity sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==
version "19.2.4"
resolved "https://registry.yarnpkg.com/react/-/react-19.2.4.tgz#438e57baa19b77cb23aab516cf635cd0579ee09a"
integrity sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==
readable-stream@^2.0.1:
version "2.3.8"
@ -8728,7 +8419,7 @@ serialize-javascript@^6.0.0, serialize-javascript@^6.0.1:
dependencies:
randombytes "^2.1.0"
serve-handler@^6.1.6, serve-handler@^6.1.7:
serve-handler@^6.1.6:
version "6.1.7"
resolved "https://registry.yarnpkg.com/serve-handler/-/serve-handler-6.1.7.tgz#e9bb864e87ee71e8dab874cde44d146b77e3fb78"
integrity sha512-CinAq1xWb0vR3twAv9evEU8cNWkXCb9kd5ePAHUKJBkOsUpR1wt/CvGdeca7vqumL1U5cSaeVQ6zZMxiJ3yWsg==
@ -9265,10 +8956,10 @@ typedarray-to-buffer@^3.1.5:
dependencies:
is-typedarray "^1.0.0"
typescript@~6.0.0:
version "6.0.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-6.0.2.tgz#0b1bfb15f68c64b97032f3d78abbf98bdbba501f"
integrity sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==
typescript@~5.9.0:
version "5.9.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.9.3.tgz#5b4f59e15310ab17a216f5d6cf53ee476ede670f"
integrity sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==
undici-types@~7.18.0:
version "7.18.2"