From 292e1aabdddddb38c054d71c90fe6021a6562eec Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 3 Feb 2026 22:27:18 +0000
Subject: [PATCH 01/19] Bump bytes from 1.11.0 to 1.11.1 (#19432)
Bumps [bytes](https://github.com/tokio-rs/bytes) from 1.11.0 to 1.11.1.
Release notes
Sourced from bytes's
releases.
Bytes v1.11.1
1.11.1 (February 3rd, 2026)
- Fix integer overflow in
BytesMut::reserve
Changelog
Sourced from bytes's
changelog.
1.11.1 (February 3rd, 2026)
- Fix integer overflow in
BytesMut::reserve
Commits
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/element-hq/synapse/network/alerts).
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
Cargo.lock | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 8d1cd967d5..e1344f89d6 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -73,9 +73,9 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
[[package]]
name = "bytes"
-version = "1.11.0"
+version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3"
+checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
[[package]]
name = "cc"
From 8d4ebc27c246de1f3088b0b0fb8a1162ec619457 Mon Sep 17 00:00:00 2001
From: Hugh Nimmo-Smith
Date: Wed, 4 Feb 2026 17:50:47 +0000
Subject: [PATCH 02/19] Fix reference to the experimental_features section of
config in the docs (#19435)
---
changelog.d/19435.doc | 1 +
docs/development/experimental_features.md | 2 +-
2 files changed, 2 insertions(+), 1 deletion(-)
create mode 100644 changelog.d/19435.doc
diff --git a/changelog.d/19435.doc b/changelog.d/19435.doc
new file mode 100644
index 0000000000..4edf2f73dc
--- /dev/null
+++ b/changelog.d/19435.doc
@@ -0,0 +1 @@
+Fix reference to the `experimental_features` section of config.
diff --git a/docs/development/experimental_features.md b/docs/development/experimental_features.md
index 5a86017ecf..a852fb88fd 100644
--- a/docs/development/experimental_features.md
+++ b/docs/development/experimental_features.md
@@ -32,7 +32,7 @@ expected and not an issue.
It is not a requirement for experimental features to be behind a configuration flag,
but one should be used if unsure.
-New experimental configuration flags should be added under the `experimental`
+New experimental configuration flags should be added under the `experimental_features`
configuration key (see the `synapse.config.experimental` file) and either explain
(briefly) what is being enabled, or include the MSC number.
The configuration flag should link to the tracking issue for the experimental feature (see below).
From f6105b73f08dd8a907687990a0a42eaf77dfc3cf Mon Sep 17 00:00:00 2001
From: Olivier 'reivilibre
Date: Thu, 5 Feb 2026 11:01:15 +0000
Subject: [PATCH 03/19] Remove support for MSC3244: Room version capabilities
as the MSC was rejected. (#19429)
Signed-off-by: Olivier 'reivilibre
---
changelog.d/19429.removal | 1 +
synapse/api/room_versions.py | 38 ------------------------
synapse/config/experimental.py | 3 --
synapse/rest/client/capabilities.py | 7 +----
tests/rest/client/test_capabilities.py | 40 --------------------------
5 files changed, 2 insertions(+), 87 deletions(-)
create mode 100644 changelog.d/19429.removal
diff --git a/changelog.d/19429.removal b/changelog.d/19429.removal
new file mode 100644
index 0000000000..b52ca2423d
--- /dev/null
+++ b/changelog.d/19429.removal
@@ -0,0 +1 @@
+Remove support for [MSC3244: Room version capabilities](https://github.com/matrix-org/matrix-spec-proposals/pull/3244) as the MSC was rejected.
\ No newline at end of file
diff --git a/synapse/api/room_versions.py b/synapse/api/room_versions.py
index 97dac661a3..2f98d7a8a8 100644
--- a/synapse/api/room_versions.py
+++ b/synapse/api/room_versions.py
@@ -18,7 +18,6 @@
#
#
-from typing import Callable
import attr
@@ -496,40 +495,3 @@ class RoomVersions:
RoomVersions.HydraV11,
)
}
-
-
-@attr.s(slots=True, frozen=True, auto_attribs=True)
-class RoomVersionCapability:
- """An object which describes the unique attributes of a room version."""
-
- identifier: str # the identifier for this capability
- preferred_version: RoomVersion | None
- support_check_lambda: Callable[[RoomVersion], bool]
-
-
-MSC3244_CAPABILITIES = {
- cap.identifier: {
- "preferred": (
- cap.preferred_version.identifier
- if cap.preferred_version is not None
- else None
- ),
- "support": [
- v.identifier
- for v in KNOWN_ROOM_VERSIONS.values()
- if cap.support_check_lambda(v)
- ],
- }
- for cap in (
- RoomVersionCapability(
- "knock",
- RoomVersions.V7,
- lambda room_version: room_version.knock_join_rule,
- ),
- RoomVersionCapability(
- "restricted",
- RoomVersions.V9,
- lambda room_version: room_version.restricted_join_rule,
- ),
- )
-}
diff --git a/synapse/config/experimental.py b/synapse/config/experimental.py
index 1bd70ead09..9b6ff482cf 100644
--- a/synapse/config/experimental.py
+++ b/synapse/config/experimental.py
@@ -385,9 +385,6 @@ def read_config(
# MSC3814 (dehydrated devices with SSSS)
self.msc3814_enabled: bool = experimental.get("msc3814_enabled", False)
- # MSC3244 (room version capabilities)
- self.msc3244_enabled: bool = experimental.get("msc3244_enabled", True)
-
# MSC3266 (room summary api)
self.msc3266_enabled: bool = experimental.get("msc3266_enabled", False)
diff --git a/synapse/rest/client/capabilities.py b/synapse/rest/client/capabilities.py
index baff999ab0..705d74dee1 100644
--- a/synapse/rest/client/capabilities.py
+++ b/synapse/rest/client/capabilities.py
@@ -21,7 +21,7 @@
from http import HTTPStatus
from typing import TYPE_CHECKING
-from synapse.api.room_versions import KNOWN_ROOM_VERSIONS, MSC3244_CAPABILITIES
+from synapse.api.room_versions import KNOWN_ROOM_VERSIONS
from synapse.http.server import HttpServer
from synapse.http.servlet import RestServlet
from synapse.http.site import SynapseRequest
@@ -77,11 +77,6 @@ async def on_GET(self, request: SynapseRequest) -> tuple[int, JsonDict]:
}
}
- if self.config.experimental.msc3244_enabled:
- response["capabilities"]["m.room_versions"][
- "org.matrix.msc3244.room_capabilities"
- ] = MSC3244_CAPABILITIES
-
if self.config.experimental.msc3720_enabled:
response["capabilities"]["org.matrix.msc3720.account_status"] = {
"enabled": True,
diff --git a/tests/rest/client/test_capabilities.py b/tests/rest/client/test_capabilities.py
index 0eec313061..2567fee2a4 100644
--- a/tests/rest/client/test_capabilities.py
+++ b/tests/rest/client/test_capabilities.py
@@ -209,46 +209,6 @@ def test_get_change_3pid_capabilities_3pid_disabled(self) -> None:
self.assertEqual(channel.code, HTTPStatus.OK)
self.assertFalse(capabilities["m.3pid_changes"]["enabled"])
- @override_config({"experimental_features": {"msc3244_enabled": False}})
- def test_get_does_not_include_msc3244_fields_when_disabled(self) -> None:
- access_token = self.get_success(
- self.auth_handler.create_access_token_for_user_id(
- self.user, device_id=None, valid_until_ms=None
- )
- )
-
- channel = self.make_request("GET", self.url, access_token=access_token)
- capabilities = channel.json_body["capabilities"]
-
- self.assertEqual(channel.code, 200)
- self.assertNotIn(
- "org.matrix.msc3244.room_capabilities", capabilities["m.room_versions"]
- )
-
- def test_get_does_include_msc3244_fields_when_enabled(self) -> None:
- access_token = self.get_success(
- self.auth_handler.create_access_token_for_user_id(
- self.user, device_id=None, valid_until_ms=None
- )
- )
-
- channel = self.make_request("GET", self.url, access_token=access_token)
- capabilities = channel.json_body["capabilities"]
-
- self.assertEqual(channel.code, 200)
- for details in capabilities["m.room_versions"][
- "org.matrix.msc3244.room_capabilities"
- ].values():
- if details["preferred"] is not None:
- self.assertTrue(
- details["preferred"] in KNOWN_ROOM_VERSIONS,
- str(details["preferred"]),
- )
-
- self.assertGreater(len(details["support"]), 0)
- for room_version in details["support"]:
- self.assertTrue(room_version in KNOWN_ROOM_VERSIONS, str(room_version))
-
def test_get_get_token_login_fields_when_disabled(self) -> None:
"""By default login via an existing session is disabled."""
access_token = self.get_success(
From 46d235cd525e2c9208e531a1b6c1adb6eae8cab8 Mon Sep 17 00:00:00 2001
From: Eric Eastwood
Date: Thu, 5 Feb 2026 17:11:55 -0600
Subject: [PATCH 04/19] Add in-repo Complement tests (#19406)
This is useful so we can test Synapse
specific behaviors like our admin API.
(see docs in PR, `complement/README.md`)
```
COMPLEMENT_DIR=../complement ./scripts-dev/complement.sh --in-repo
```
Complement calls these
["out-of-repo"](https://github.com/matrix-org/complement/blob/78c255edcebfcb0ac5e3c86d49d76cb21fdd035a/OUT-OF-REPO-TESTS.md)
tests but it's a bit of a misnomer once they're in your project. (just
depends on the perspective)
There has been [previous
desire](https://github.com/element-hq/synapse/pull/19021#discussion_r2453442191)
for this kind of thing but this is spawning from wanting to have some
tests for our purge history admin API
(https://github.com/element-hq/synapse-rust-apps/issues/430). There are
some Sytest tests ([`matrix-org/sytest` ->
`tests/48admin.pl#L91-L618`](https://github.com/matrix-org/sytest/blob/1be04cce46c0f84abac736390dc3fab17f35a756/tests/48admin.pl#L91-L618))
for this already but I'd much rather work in Complement instead of
Sytest. I'm wanting these tests to ensure that our new `event-cache`
rust app for Synapse Pro doesn't break these kind of erasure features
(https://github.com/element-hq/synapse-rust-apps/issues/366 and
https://github.com/element-hq/synapse-rust-apps/issues/153).
Interestingly, there is already [`matrix-org/complement` ->
`tests/csapi/admin_test.go`](https://github.com/matrix-org/complement/blob/78c255edcebfcb0ac5e3c86d49d76cb21fdd035a/tests/csapi/admin_test.go)
(added in https://github.com/matrix-org/complement/pull/322) in the
Complement repo iteslf that tests the
`/_synapse/admin/v1/send_server_notice` endpoint but it's a bit of an
interesting case as [Dendrite also supports this
endpoint](https://github.com/matrix-org/dendrite/pull/2180). I don't
think it's good practice to continually shove in more and more
Synapse-specific behavior into the Complement repo itself.
We already have success with other out-of-repo tests for projects like
the
[SBG](https://github.com/element-hq/sbg/tree/b76b05b53e40bf6890e51dd1b83cec3460274eb2/complement_tests),
[TI-Messenger
Proxy](https://github.com/element-hq/ti-messenger-proxy/tree/c8fa87feccc743c01cccbbc2685321206b532925/complement),
and our [Synapse Pro for small
hosts](https://github.com/element-hq/synapse-small-hosts/tree/c2ea7eabf3e1d7c26a5312ebef326b254937be99/complement).
---
.github/workflows/latest_deps.yml | 50 ++-
.github/workflows/tests.yml | 30 +-
.github/workflows/twisted_trunk.yml | 52 ++-
changelog.d/19406.misc | 1 +
complement/.golangci.yml | 38 ++
complement/README.md | 54 +++
complement/go.mod | 209 ++++++++++
complement/go.sum | 587 ++++++++++++++++++++++++++++
complement/tests/federation_test.go | 65 +++
complement/tests/main_test.go | 23 ++
scripts-dev/complement.sh | 45 ++-
scripts-dev/lint.sh | 11 +
12 files changed, 1144 insertions(+), 21 deletions(-)
create mode 100644 changelog.d/19406.misc
create mode 100644 complement/.golangci.yml
create mode 100644 complement/README.md
create mode 100644 complement/go.mod
create mode 100644 complement/go.sum
create mode 100644 complement/tests/federation_test.go
create mode 100644 complement/tests/main_test.go
diff --git a/.github/workflows/latest_deps.yml b/.github/workflows/latest_deps.yml
index 9e0f2c384e..dda4e5f57b 100644
--- a/.github/workflows/latest_deps.yml
+++ b/.github/workflows/latest_deps.yml
@@ -126,7 +126,6 @@ jobs:
-exec echo "::endgroup::" \;
|| true
-
sytest:
needs: check_repo
if: needs.check_repo.outputs.should_run_workflow == 'true'
@@ -181,7 +180,6 @@ jobs:
/logs/results.tap
/logs/**/*.log*
-
complement:
needs: check_repo
if: "!failure() && !cancelled() && needs.check_repo.outputs.should_run_workflow == 'true'"
@@ -214,11 +212,53 @@ jobs:
cache-dependency-path: complement/go.sum
go-version-file: complement/go.mod
- - run: |
+ - name: Run Complement Tests
+ id: run_complement_tests
+ # -p=1: We're using `-p 1` to force the test packages to run serially as GHA boxes
+ # are underpowered and don't like running tons of Synapse instances at once.
+ # -json: Output JSON format so that gotestfmt can parse it.
+ #
+ # tee /tmp/gotest-complement.log: We tee the output to a file so that we can re-process it
+ # later on for better formatting with gotestfmt. But we still want the command
+ # to output to the terminal as it runs so we can see what's happening in
+ # real-time.
+ run: |
set -o pipefail
- TEST_ONLY_IGNORE_POETRY_LOCKFILE=1 POSTGRES=${{ (matrix.database == 'Postgres') && 1 || '' }} WORKERS=${{ (matrix.arrangement == 'workers') && 1 || '' }} COMPLEMENT_DIR=`pwd`/complement synapse/scripts-dev/complement.sh -json 2>&1 | synapse/.ci/scripts/gotestfmt
+ COMPLEMENT_DIR=`pwd`/complement synapse/scripts-dev/complement.sh -p 1 -json 2>&1 | tee /tmp/gotest-complement.log
shell: bash
- name: Run Complement Tests
+ env:
+ POSTGRES: ${{ (matrix.database == 'Postgres') && 1 || '' }}
+ WORKERS: ${{ (matrix.arrangement == 'workers') && 1 || '' }}
+ TEST_ONLY_IGNORE_POETRY_LOCKFILE: 1
+
+ - name: Formatted Complement test logs
+ # Always run this step if we attempted to run the Complement tests.
+ if: always() && steps.run_complement_tests.outcome != 'skipped'
+ run: cat /tmp/gotest-complement.log | gotestfmt -hide "successful-downloads,empty-packages"
+
+ - name: Run in-repo Complement Tests
+ id: run_in_repo_complement_tests
+ # -p=1: We're using `-p 1` to force the test packages to run serially as GHA boxes
+ # are underpowered and don't like running tons of Synapse instances at once.
+ # -json: Output JSON format so that gotestfmt can parse it.
+ #
+ # tee /tmp/gotest-in-repo-complement.log: We tee the output to a file so that we can re-process it
+ # later on for better formatting with gotestfmt. But we still want the command
+ # to output to the terminal as it runs so we can see what's happening in
+ # real-time.
+ run: |
+ set -o pipefail
+ COMPLEMENT_DIR=`pwd`/complement synapse/scripts-dev/complement.sh --in-repo -p 1 -json 2>&1 | tee /tmp/gotest-in-repo-complement.log
+ shell: bash
+ env:
+ POSTGRES: ${{ (matrix.database == 'Postgres') && 1 || '' }}
+ WORKERS: ${{ (matrix.arrangement == 'workers') && 1 || '' }}
+ TEST_ONLY_IGNORE_POETRY_LOCKFILE: 1
+
+ - name: Formatted in-repo Complement test logs
+ # Always run this step if we attempted to run the Complement tests.
+ if: always() && steps.run_in_repo_complement_tests.outcome != 'skipped'
+ run: cat /tmp/gotest-in-repo-complement.log | gotestfmt -hide "successful-downloads,empty-packages"
# Open an issue if the build fails, so we know about it.
# Only do this if we're not experimenting with this action in a PR.
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 715dfa93d9..f575adb5c5 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -707,20 +707,19 @@ jobs:
cache-dependency-path: complement/go.sum
go-version-file: complement/go.mod
- # use p=1 concurrency as GHA boxes are underpowered and don't like running tons of synapses at once.
- name: Run Complement Tests
id: run_complement_tests
# -p=1: We're using `-p 1` to force the test packages to run serially as GHA boxes
# are underpowered and don't like running tons of Synapse instances at once.
# -json: Output JSON format so that gotestfmt can parse it.
#
- # tee /tmp/gotest.log: We tee the output to a file so that we can re-process it
+ # tee /tmp/gotest-complement.log: We tee the output to a file so that we can re-process it
# later on for better formatting with gotestfmt. But we still want the command
# to output to the terminal as it runs so we can see what's happening in
# real-time.
run: |
set -o pipefail
- COMPLEMENT_DIR=`pwd`/complement synapse/scripts-dev/complement.sh -p 1 -json 2>&1 | tee /tmp/gotest.log
+ COMPLEMENT_DIR=`pwd`/complement synapse/scripts-dev/complement.sh -p 1 -json 2>&1 | tee /tmp/gotest-complement.log
shell: bash
env:
POSTGRES: ${{ (matrix.database == 'Postgres') && 1 || '' }}
@@ -729,7 +728,30 @@ jobs:
- name: Formatted Complement test logs
# Always run this step if we attempted to run the Complement tests.
if: always() && steps.run_complement_tests.outcome != 'skipped'
- run: cat /tmp/gotest.log | gotestfmt -hide "successful-downloads,empty-packages"
+ run: cat /tmp/gotest-complement.log | gotestfmt -hide "successful-downloads,empty-packages"
+
+ - name: Run in-repo Complement Tests
+ id: run_in_repo_complement_tests
+ # -p=1: We're using `-p 1` to force the test packages to run serially as GHA boxes
+ # are underpowered and don't like running tons of Synapse instances at once.
+ # -json: Output JSON format so that gotestfmt can parse it.
+ #
+ # tee /tmp/gotest-in-repo-complement.log: We tee the output to a file so that we can re-process it
+ # later on for better formatting with gotestfmt. But we still want the command
+ # to output to the terminal as it runs so we can see what's happening in
+ # real-time.
+ run: |
+ set -o pipefail
+ COMPLEMENT_DIR=`pwd`/complement synapse/scripts-dev/complement.sh --in-repo -p 1 -json 2>&1 | tee /tmp/gotest-in-repo-complement.log
+ shell: bash
+ env:
+ POSTGRES: ${{ (matrix.database == 'Postgres') && 1 || '' }}
+ WORKERS: ${{ (matrix.arrangement == 'workers') && 1 || '' }}
+
+ - name: Formatted in-repo Complement test logs
+ # Always run this step if we attempted to run the Complement tests.
+ if: always() && steps.run_in_repo_complement_tests.outcome != 'skipped'
+ run: cat /tmp/gotest-in-repo-complement.log | gotestfmt -hide "successful-downloads,empty-packages"
cargo-test:
if: ${{ needs.changes.outputs.rust == 'true' }}
diff --git a/.github/workflows/twisted_trunk.yml b/.github/workflows/twisted_trunk.yml
index bd5c79f16d..12fdbbe7c4 100644
--- a/.github/workflows/twisted_trunk.yml
+++ b/.github/workflows/twisted_trunk.yml
@@ -12,10 +12,9 @@ on:
twisted_ref:
description: Commit, branch or tag to checkout from upstream Twisted.
required: false
- default: 'trunk'
+ default: "trunk"
type: string
-
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
@@ -89,7 +88,6 @@ jobs:
poetry add --extras tls git+https://github.com/twisted/twisted.git#trunk
poetry install --no-interaction --extras "all test"
- run: poetry run trial --jobs 2 tests
-
- name: Dump logs
# Logs are most useful when the command fails, always include them.
if: ${{ always() }}
@@ -199,11 +197,53 @@ jobs:
poetry lock
working-directory: synapse
- - run: |
+ - name: Run Complement Tests
+ id: run_complement_tests
+ # -p=1: We're using `-p 1` to force the test packages to run serially as GHA boxes
+ # are underpowered and don't like running tons of Synapse instances at once.
+ # -json: Output JSON format so that gotestfmt can parse it.
+ #
+ # tee /tmp/gotest-complement.log: We tee the output to a file so that we can re-process it
+ # later on for better formatting with gotestfmt. But we still want the command
+ # to output to the terminal as it runs so we can see what's happening in
+ # real-time.
+ run: |
set -o pipefail
- TEST_ONLY_SKIP_DEP_HASH_VERIFICATION=1 POSTGRES=${{ (matrix.database == 'Postgres') && 1 || '' }} WORKERS=${{ (matrix.arrangement == 'workers') && 1 || '' }} COMPLEMENT_DIR=`pwd`/complement synapse/scripts-dev/complement.sh -json 2>&1 | synapse/.ci/scripts/gotestfmt
+ COMPLEMENT_DIR=`pwd`/complement synapse/scripts-dev/complement.sh -p 1 -json 2>&1 | tee /tmp/gotest-complement.log
shell: bash
- name: Run Complement Tests
+ env:
+ POSTGRES: ${{ (matrix.database == 'Postgres') && 1 || '' }}
+ WORKERS: ${{ (matrix.arrangement == 'workers') && 1 || '' }}
+ TEST_ONLY_SKIP_DEP_HASH_VERIFICATION: 1
+
+ - name: Formatted Complement test logs
+ # Always run this step if we attempted to run the Complement tests.
+ if: always() && steps.run_complement_tests.outcome != 'skipped'
+ run: cat /tmp/gotest-complement.log | gotestfmt -hide "successful-downloads,empty-packages"
+
+ - name: Run in-repo Complement Tests
+ id: run_in_repo_complement_tests
+ # -p=1: We're using `-p 1` to force the test packages to run serially as GHA boxes
+ # are underpowered and don't like running tons of Synapse instances at once.
+ # -json: Output JSON format so that gotestfmt can parse it.
+ #
+ # tee /tmp/gotest-in-repo-complement.log: We tee the output to a file so that we can re-process it
+ # later on for better formatting with gotestfmt. But we still want the command
+ # to output to the terminal as it runs so we can see what's happening in
+ # real-time.
+ run: |
+ set -o pipefail
+ COMPLEMENT_DIR=`pwd`/complement synapse/scripts-dev/complement.sh --in-repo -p 1 -json 2>&1 | tee /tmp/gotest-in-repo-complement.log
+ shell: bash
+ env:
+ POSTGRES: ${{ (matrix.database == 'Postgres') && 1 || '' }}
+ WORKERS: ${{ (matrix.arrangement == 'workers') && 1 || '' }}
+ TEST_ONLY_SKIP_DEP_HASH_VERIFICATION: 1
+
+ - name: Formatted in-repo Complement test logs
+ # Always run this step if we attempted to run the Complement tests.
+ if: always() && steps.run_in_repo_complement_tests.outcome != 'skipped'
+ run: cat /tmp/gotest-in-repo-complement.log | gotestfmt -hide "successful-downloads,empty-packages"
# open an issue if the build fails, so we know about it.
open-issue:
diff --git a/changelog.d/19406.misc b/changelog.d/19406.misc
new file mode 100644
index 0000000000..bfe8d6afb0
--- /dev/null
+++ b/changelog.d/19406.misc
@@ -0,0 +1 @@
+Add in-repo Complement tests so we can test Synapse specific behavior at an end-to-end level.
diff --git a/complement/.golangci.yml b/complement/.golangci.yml
new file mode 100644
index 0000000000..6ef564d4c4
--- /dev/null
+++ b/complement/.golangci.yml
@@ -0,0 +1,38 @@
+# Docs: https://golangci-lint.run/docs/configuration/file/
+#
+# Go formatting/linting rules
+#
+# This is run as part of the normal linting utility script,
+# `poetry run ./scripts-dev/lint.sh`
+
+version: "2"
+
+linters:
+ # Default set of linters.
+ # The value can be:
+ # - `standard`: https://golangci-lint.run/docs/linters/#enabled-by-default
+ # - `all`: enables all linters by default.
+ # - `none`: disables all linters by default.
+ # - `fast`: enables only linters considered as "fast" (`golangci-lint help linters --json | jq '[ .[] | select(.fast==true) ] | map(.name)'`).
+ # Default: standard
+ default: standard
+
+ # Enable specific linter.
+ # enable:
+ # - example
+
+ # Disable specific linters.
+ disable:
+ # FIXME: Ideally, we'd enable the `bodyclose` lint but there are many
+ # false-positives (like https://github.com/timakin/bodyclose/issues/39) and just is
+ # not well-suited for our use case (https://github.com/timakin/bodyclose/issues/11 and
+ # https://github.com/timakin/bodyclose/issues/76).
+ - bodyclose
+
+formatters:
+ # Enable specific formatter.
+ # Default: [] (uses standard Go formatting)
+ enable:
+ - gofmt
+ - goimports
+ - golines
diff --git a/complement/README.md b/complement/README.md
new file mode 100644
index 0000000000..c4a95bdd63
--- /dev/null
+++ b/complement/README.md
@@ -0,0 +1,54 @@
+# Complement testing
+
+Complement is a black box integration testing framework for Matrix homeservers. It
+allows us to write end-to-end tests that interact with real Synapse homeservers to
+ensure everything works at a holistic level.
+
+
+## Setup
+
+Nothing beyond a [normal Complement
+setup](https://github.com/matrix-org/complement?tab=readme-ov-file#running) (just Go and
+Docker).
+
+
+## Running tests
+
+Run tests from the [Complement](https://github.com/matrix-org/complement) repo:
+
+```shell
+# Run the tests
+./scripts-dev/complement.sh
+
+# To run a whole group of tests, you can specify part of the test path:
+scripts-dev/complement.sh ./tests/csapi/... -run TestRoomCreate
+# To run a specific test, you can specify the whole name structure:
+scripts-dev/complement.sh ./tests/csapi/... -run TestRoomCreate/Parallel/POST_/createRoom_makes_a_public_room
+# Generally though, the `-run` parameter accepts regex patterns, so you can match however you like:
+scripts-dev/complement.sh ./tests/... -run 'TestRoomCreate/Parallel/POST_/createRoom_makes_a_(.*)'
+```
+
+Typically, if you're developing the Synapse and Complement tests side-by-side, you will
+run something like this:
+
+```shell
+# To run a specific test
+COMPLEMENT_DIR=../complement ./scripts-dev/complement.sh ./tests/csapi/... -run TestRoomCreate
+```
+
+
+### Running in-repo tests
+
+In-repo Complement tests are tests that are vendored into this project. We use the
+in-repo test suite to test Synapse specific behaviors like the admin API.
+
+To run the in-repo Complement tests, use the `--in-repo` command line argument.
+
+```shell
+# Run only a specific test package.
+# Note: test packages are relative to the `./complement` directory in this project
+./scripts-dev/complement.sh --in-repo ./tests/...
+
+# Similarly, you can also use `-run` to specify all or part of a specific test path to run
+scripts-dev/complement.sh --in-repo ./tests/... -run TestIntraShardFederation
+```
diff --git a/complement/go.mod b/complement/go.mod
new file mode 100644
index 0000000000..062ea8e6ee
--- /dev/null
+++ b/complement/go.mod
@@ -0,0 +1,209 @@
+module github.com/element-hq/synapse
+
+go 1.24.1
+
+toolchain go1.24.4
+
+require (
+ github.com/docker/docker v28.2.2+incompatible
+ github.com/docker/go-connections v0.5.0
+ github.com/matrix-org/complement v0.0.0-20251120181401-44111a2a8a9d
+ github.com/matrix-org/gomatrixserverlib v0.0.0-20250813150445-9f5070a65744
+ github.com/minio/operator v0.0.0-20250423184541-6eee6a7caa70
+ github.com/mittwald/go-helm-client v0.12.18
+ gopkg.in/yaml.v2 v2.4.0
+ k8s.io/api v0.33.2
+ k8s.io/apimachinery v0.33.2
+ k8s.io/client-go v0.33.2
+ sigs.k8s.io/controller-runtime v0.21.0
+)
+
+require (
+ github.com/cloudnative-pg/barman-cloud v0.3.1 // indirect
+ github.com/cloudnative-pg/machinery v0.2.0 // indirect
+ github.com/dustin/go-humanize v1.0.1 // indirect
+ github.com/evanphx/json-patch/v5 v5.9.11 // indirect
+ github.com/fsnotify/fsnotify v1.8.0 // indirect
+ github.com/go-ini/ini v1.67.0 // indirect
+ github.com/go-logr/zapr v1.3.0 // indirect
+ github.com/go-ole/go-ole v1.3.0 // indirect
+ github.com/goccy/go-json v0.10.5 // indirect
+ github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
+ github.com/golang/protobuf v1.5.4 // indirect
+ github.com/hashicorp/go-set/v3 v3.0.0 // indirect
+ github.com/klauspost/cpuid/v2 v2.2.10 // indirect
+ github.com/kubernetes-csi/external-snapshotter/client/v8 v8.2.0 // indirect
+ github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 // indirect
+ github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530 // indirect
+ github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
+ github.com/miekg/dns v1.1.66 // indirect
+ github.com/minio/crc64nvme v1.0.1 // indirect
+ github.com/minio/madmin-go/v3 v3.0.100 // indirect
+ github.com/minio/md5-simd v1.1.2 // indirect
+ github.com/minio/minio-go/v7 v7.0.89 // indirect
+ github.com/moby/sys/atomicwriter v0.1.0 // indirect
+ github.com/oleiade/lane/v2 v2.0.0 // indirect
+ github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c // indirect
+ github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
+ github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.80.1 // indirect
+ github.com/prometheus/prom2json v1.4.1 // indirect
+ github.com/prometheus/prometheus v0.302.1 // indirect
+ github.com/rs/xid v1.6.0 // indirect
+ github.com/safchain/ethtool v0.5.10 // indirect
+ github.com/secure-io/sio-go v0.3.1 // indirect
+ github.com/shirou/gopsutil/v3 v3.24.5 // indirect
+ github.com/shoenig/go-m1cpu v0.1.6 // indirect
+ github.com/tinylib/msgp v1.2.5 // indirect
+ github.com/tklauser/go-sysconf v0.3.15 // indirect
+ github.com/tklauser/numcpus v0.10.0 // indirect
+ github.com/yusufpapurcu/wmi v1.2.4 // indirect
+ go.uber.org/multierr v1.11.0 // indirect
+ go.uber.org/zap v1.27.0 // indirect
+ golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
+ golang.org/x/mod v0.29.0 // indirect
+ golang.org/x/tools v0.38.0 // indirect
+ gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
+ gotest.tools/v3 v3.4.0 // indirect
+ oras.land/oras-go/v2 v2.6.0 // indirect
+)
+
+require (
+ dario.cat/mergo v1.0.1 // indirect
+ github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
+ github.com/BurntSushi/toml v1.5.0 // indirect
+ github.com/MakeNowJust/heredoc v1.0.0 // indirect
+ github.com/Masterminds/goutils v1.1.1 // indirect
+ github.com/Masterminds/semver/v3 v3.3.1 // indirect
+ github.com/Masterminds/sprig/v3 v3.3.0 // indirect
+ github.com/Masterminds/squirrel v1.5.4 // indirect
+ github.com/Microsoft/go-winio v0.6.2 // indirect
+ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
+ github.com/beorn7/perks v1.0.1 // indirect
+ github.com/blang/semver/v4 v4.0.0 // indirect
+ github.com/cespare/xxhash/v2 v2.3.0 // indirect
+ github.com/chai2010/gettext-go v1.0.2 // indirect
+ github.com/cloudnative-pg/cloudnative-pg v1.26.0
+ github.com/containerd/containerd v1.7.27 // indirect
+ github.com/containerd/errdefs v1.0.0 // indirect
+ github.com/containerd/errdefs/pkg v0.3.0 // indirect
+ github.com/containerd/log v0.1.0 // indirect
+ github.com/containerd/platforms v0.2.1 // indirect
+ github.com/cyphar/filepath-securejoin v0.4.1 // indirect
+ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
+ github.com/distribution/reference v0.6.0 // indirect
+ github.com/docker/go-units v0.5.0 // indirect
+ github.com/emicklei/go-restful/v3 v3.12.2 // indirect
+ github.com/evanphx/json-patch v5.9.11+incompatible // indirect
+ github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect
+ github.com/fatih/color v1.18.0 // indirect
+ github.com/felixge/httpsnoop v1.0.4 // indirect
+ github.com/fxamacker/cbor/v2 v2.7.0 // indirect
+ github.com/go-errors/errors v1.5.1 // indirect
+ github.com/go-gorp/gorp/v3 v3.1.0 // indirect
+ github.com/go-logr/logr v1.4.3 // indirect
+ github.com/go-logr/stdr v1.2.2 // indirect
+ github.com/go-openapi/jsonpointer v0.21.1 // indirect
+ github.com/go-openapi/jsonreference v0.21.0 // indirect
+ github.com/go-openapi/swag v0.23.1 // indirect
+ github.com/gobwas/glob v0.2.3 // indirect
+ github.com/gogo/protobuf v1.3.2 // indirect
+ github.com/google/btree v1.1.3 // indirect
+ github.com/google/gnostic-models v0.6.9 // indirect
+ github.com/google/go-cmp v0.7.0 // indirect
+ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
+ github.com/google/uuid v1.6.0 // indirect
+ github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
+ github.com/gosuri/uitable v0.0.4 // indirect
+ github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
+ github.com/hashicorp/errwrap v1.1.0 // indirect
+ github.com/hashicorp/go-multierror v1.1.1 // indirect
+ github.com/huandu/xstrings v1.5.0 // indirect
+ github.com/inconshreveable/mousetrap v1.1.0 // indirect
+ github.com/jmoiron/sqlx v1.4.0 // indirect
+ github.com/josharian/intern v1.0.0 // indirect
+ github.com/json-iterator/go v1.1.12 // indirect
+ github.com/klauspost/compress v1.18.0 // indirect
+ github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
+ github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
+ github.com/lib/pq v1.10.9 // indirect
+ github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
+ github.com/mailru/easyjson v0.9.0 // indirect
+ github.com/matrix-org/util v0.0.0-20221111132719-399730281e66 // indirect
+ github.com/mattn/go-colorable v0.1.14 // indirect
+ github.com/mattn/go-isatty v0.0.20 // indirect
+ github.com/mattn/go-runewidth v0.0.15 // indirect
+ github.com/mitchellh/copystructure v1.2.0 // indirect
+ github.com/mitchellh/go-wordwrap v1.0.1 // indirect
+ github.com/mitchellh/reflectwalk v1.0.2 // indirect
+ github.com/moby/docker-image-spec v1.3.1 // indirect
+ github.com/moby/spdystream v0.5.0 // indirect
+ github.com/moby/term v0.5.2 // indirect
+ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
+ github.com/modern-go/reflect2 v1.0.2 // indirect
+ github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
+ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
+ github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
+ github.com/opencontainers/go-digest v1.0.0 // indirect
+ github.com/opencontainers/image-spec v1.1.1 // indirect
+ github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
+ github.com/pkg/errors v0.9.1 // indirect
+ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
+ github.com/prometheus/client_golang v1.22.0 // indirect
+ github.com/prometheus/client_model v0.6.2
+ github.com/prometheus/common v0.65.0
+ github.com/prometheus/procfs v0.16.0 // indirect
+ github.com/rivo/uniseg v0.4.4 // indirect
+ github.com/rubenv/sql-migrate v1.8.0 // indirect
+ github.com/russross/blackfriday/v2 v2.1.0 // indirect
+ github.com/shopspring/decimal v1.4.0 // indirect
+ github.com/sirupsen/logrus v1.9.3 // indirect
+ github.com/spf13/cast v1.7.0 // indirect
+ github.com/spf13/cobra v1.9.1 // indirect
+ github.com/spf13/pflag v1.0.6 // indirect
+ github.com/stretchr/testify v1.10.0
+ github.com/tidwall/gjson v1.18.0 // indirect
+ github.com/tidwall/match v1.1.1 // indirect
+ github.com/tidwall/pretty v1.2.1 // indirect
+ github.com/tidwall/sjson v1.2.5 // indirect
+ github.com/x448/float16 v0.8.4 // indirect
+ github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
+ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
+ github.com/xeipuuv/gojsonschema v1.2.0 // indirect
+ github.com/xlab/treeprint v1.2.0 // indirect
+ go.opentelemetry.io/auto/sdk v1.1.0 // indirect
+ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
+ go.opentelemetry.io/otel v1.36.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0 // indirect
+ go.opentelemetry.io/otel/metric v1.36.0 // indirect
+ go.opentelemetry.io/otel/trace v1.36.0 // indirect
+ go.opentelemetry.io/proto/otlp v1.7.0 // indirect
+ golang.org/x/crypto v0.45.0 // indirect
+ golang.org/x/net v0.47.0 // indirect
+ golang.org/x/oauth2 v0.30.0 // indirect
+ golang.org/x/sync v0.18.0 // indirect
+ golang.org/x/sys v0.38.0 // indirect
+ golang.org/x/term v0.37.0 // indirect
+ golang.org/x/text v0.31.0 // indirect
+ golang.org/x/time v0.11.0 // indirect
+ google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect
+ google.golang.org/grpc v1.72.2 // indirect
+ google.golang.org/protobuf v1.36.6 // indirect
+ gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
+ gopkg.in/inf.v0 v0.9.1 // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
+ helm.sh/helm/v3 v3.18.4 // indirect
+ k8s.io/apiextensions-apiserver v0.33.2 // indirect
+ k8s.io/apiserver v0.33.2 // indirect
+ k8s.io/cli-runtime v0.33.2 // indirect
+ k8s.io/component-base v0.33.2 // indirect
+ k8s.io/klog/v2 v2.130.1
+ k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
+ k8s.io/kubectl v0.33.2 // indirect
+ k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979 // indirect
+ sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
+ sigs.k8s.io/kustomize/api v0.19.0 // indirect
+ sigs.k8s.io/kustomize/kyaml v0.19.0 // indirect
+ sigs.k8s.io/randfill v1.0.0 // indirect
+ sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect
+ sigs.k8s.io/yaml v1.4.0 // indirect
+)
diff --git a/complement/go.sum b/complement/go.sum
new file mode 100644
index 0000000000..2ff8608953
--- /dev/null
+++ b/complement/go.sum
@@ -0,0 +1,587 @@
+dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
+dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
+filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
+filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
+github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
+github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
+github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
+github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
+github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
+github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
+github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU=
+github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
+github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
+github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
+github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
+github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
+github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4=
+github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
+github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs=
+github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0=
+github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM=
+github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10=
+github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
+github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
+github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
+github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
+github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
+github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
+github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
+github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
+github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70=
+github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
+github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
+github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
+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/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk=
+github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA=
+github.com/cloudnative-pg/barman-cloud v0.3.1 h1:kzkY77k2lN/caoyh7ibXDSZjJeSJTNvnVt6Gfa8Iq5M=
+github.com/cloudnative-pg/barman-cloud v0.3.1/go.mod h1:4HL3AjY9oEl2Ed0HSkyvTZEQPhwyFOaAnuCz9lfVeYQ=
+github.com/cloudnative-pg/cloudnative-pg v1.26.0 h1:X+ayWg6TXqglziSPejKiviPTf/CSh4AmYXx1mrS3i8s=
+github.com/cloudnative-pg/cloudnative-pg v1.26.0/go.mod h1:aNh0g7UHKxyka4HYOqLaYDWtZ6tORQ7HbIHLvb79sx8=
+github.com/cloudnative-pg/machinery v0.2.0 h1:x8OAwxdeL/6wkbxqorz+nX6UovTyx7/TBeCfiRebR2o=
+github.com/cloudnative-pg/machinery v0.2.0/go.mod h1:Kg8W8Tb/1UFGGtw3hR8S5SytSWddlHaCnJSgBo4x/nc=
+github.com/containerd/containerd v1.7.27 h1:yFyEyojddO3MIGVER2xJLWoCIn+Up4GaHFquP7hsFII=
+github.com/containerd/containerd v1.7.27/go.mod h1:xZmPnl75Vc+BLGt4MIfu6bp+fy03gdHAn9bz+FreFR0=
+github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
+github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
+github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
+github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
+github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
+github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
+github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
+github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=
+github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
+github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
+github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
+github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
+github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
+github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
+github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
+github.com/distribution/distribution/v3 v3.0.0 h1:q4R8wemdRQDClzoNNStftB2ZAfqOiN6UX90KJc4HjyM=
+github.com/distribution/distribution/v3 v3.0.0/go.mod h1:tRNuFoZsUdyRVegq8xGNeds4KLjwLCRin/tTo6i1DhU=
+github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
+github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
+github.com/docker/docker v28.2.2+incompatible h1:CjwRSksz8Yo4+RmQ339Dp/D2tGO5JxwYeqtMOEe0LDw=
+github.com/docker/docker v28.2.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/docker-credential-helpers v0.9.3 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqIjCBS4wrsOh9yRqcz8=
+github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo=
+github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
+github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
+github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8=
+github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
+github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8=
+github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
+github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
+github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
+github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
+github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
+github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU=
+github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
+github.com/evanphx/json-patch v5.9.11+incompatible h1:ixHHqfcGvxhWkniF1tWxBHA0yb4Z+d1UQi45df52xW8=
+github.com/evanphx/json-patch v5.9.11+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
+github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU=
+github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM=
+github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4=
+github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc=
+github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
+github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
+github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
+github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
+github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7DlmewI=
+github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk=
+github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
+github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
+github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
+github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
+github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
+github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
+github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk=
+github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
+github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs=
+github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw=
+github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
+github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
+github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
+github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
+github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
+github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
+github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
+github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
+github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
+github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
+github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
+github.com/go-openapi/jsonpointer v0.21.1 h1:whnzv/pNXtK2FbX/W9yJfRmE2gsmkfahjMKB0fZvcic=
+github.com/go-openapi/jsonpointer v0.21.1/go.mod h1:50I1STOfbY1ycR8jGz8DaMeLCdXiI6aDteEdRNNzpdk=
+github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
+github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
+github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU=
+github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0=
+github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
+github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
+github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
+github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
+github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
+github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
+github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
+github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=
+github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
+github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
+github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
+github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
+github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw=
+github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
+github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
+github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8=
+github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
+github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
+github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE=
+github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w=
+github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
+github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
+github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
+github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
+github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY=
+github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo=
+github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
+github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
+github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
+github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
+github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
+github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
+github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
+github.com/hashicorp/go-set/v3 v3.0.0 h1:CaJBQvQCOWoftrBcDt7Nwgo0kdpmrKxar/x2o6pV9JA=
+github.com/hashicorp/go-set/v3 v3.0.0/go.mod h1:IEghM2MpE5IaNvL+D7X480dfNtxjRXZ6VMpK3C8s2ok=
+github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4=
+github.com/hashicorp/golang-lru/arc/v2 v2.0.5 h1:l2zaLDubNhW4XO3LnliVj0GXO3+/CGNJAg1dcN2Fpfw=
+github.com/hashicorp/golang-lru/arc/v2 v2.0.5/go.mod h1:ny6zBSQZi2JxIeYcv7kt2sH2PXJtirBN7RDhRpxPkxU=
+github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4=
+github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
+github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
+github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
+github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
+github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
+github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
+github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
+github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
+github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
+github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
+github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
+github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
+github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
+github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
+github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/kubernetes-csi/external-snapshotter/client/v8 v8.2.0 h1:Q3jQ1NkFqv5o+F8dMmHd8SfEmlcwNeo1immFApntEwE=
+github.com/kubernetes-csi/external-snapshotter/client/v8 v8.2.0/go.mod h1:E3vdYxHj2C2q6qo8/Da4g7P+IcwqRZyy3gJBzYybV9Y=
+github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
+github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
+github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw=
+github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
+github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk=
+github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
+github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
+github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
+github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
+github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 h1:PpXWgLPs+Fqr325bN2FD2ISlRRztXibcX6e8f5FR5Dc=
+github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
+github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
+github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
+github.com/matrix-org/complement v0.0.0-20251120181401-44111a2a8a9d h1:s2Xc9GB2E/pXdElP18h8+04Y3SmhaII7xh2YmCM7oZc=
+github.com/matrix-org/complement v0.0.0-20251120181401-44111a2a8a9d/go.mod h1:HioTV089DHLBfljH9QLGifJRE4Avnyk08BXXhCwd4gs=
+github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530 h1:kHKxCOLcHH8r4Fzarl4+Y3K5hjothkVW5z7T1dUM11U=
+github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s=
+github.com/matrix-org/gomatrixserverlib v0.0.0-20250813150445-9f5070a65744 h1:5GvC2FD9O/PhuyY95iJQdNYHbDioEhMWdeMP9maDUL8=
+github.com/matrix-org/gomatrixserverlib v0.0.0-20250813150445-9f5070a65744/go.mod h1:b6KVfDjXjA5Q7vhpOaMqIhFYvu5BuFVZixlNeTV/CLc=
+github.com/matrix-org/util v0.0.0-20221111132719-399730281e66 h1:6z4KxomXSIGWqhHcfzExgkH3Z3UkIXry4ibJS4Aqz2Y=
+github.com/matrix-org/util v0.0.0-20221111132719-399730281e66/go.mod h1:iBI1foelCqA09JJgPV0FYz4qA5dUXYOxMi57FxKBdd4=
+github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
+github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
+github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
+github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
+github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
+github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
+github.com/miekg/dns v1.1.66 h1:FeZXOS3VCVsKnEAd+wBkjMC3D2K+ww66Cq3VnCINuJE=
+github.com/miekg/dns v1.1.66/go.mod h1:jGFzBsSNbJw6z1HYut1RKBKHA9PBdxeHrZG8J+gC2WE=
+github.com/minio/crc64nvme v1.0.1 h1:DHQPrYPdqK7jQG/Ls5CTBZWeex/2FMS3G5XGkycuFrY=
+github.com/minio/crc64nvme v1.0.1/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg=
+github.com/minio/madmin-go/v3 v3.0.100 h1:1gsy1kHgk8v9ZQyEU/L9k1ZoImFid+hlzwrOgUULB88=
+github.com/minio/madmin-go/v3 v3.0.100/go.mod h1:pMLdj9OtN0CANNs5tdm6opvOlDFfj0WhbztboZAjRWE=
+github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
+github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
+github.com/minio/minio-go/v7 v7.0.89 h1:hx4xV5wwTUfyv8LarhJAwNecnXpoTsj9v3f3q/ZkiJU=
+github.com/minio/minio-go/v7 v7.0.89/go.mod h1:2rFnGAp02p7Dddo1Fq4S2wYOfpF0MUTSeLTRC90I204=
+github.com/minio/operator v0.0.0-20250423184541-6eee6a7caa70 h1:CTpACn2vNMA76TXKGufGhxVa9KIw3Qdvtx6j/l5fKeE=
+github.com/minio/operator v0.0.0-20250423184541-6eee6a7caa70/go.mod h1:NL8ANdLUtI70DmG2x2EMCfoe6d3ijD1Xok/N1Tr8Czo=
+github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
+github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
+github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
+github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
+github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
+github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
+github.com/mittwald/go-helm-client v0.12.18 h1:i9cJNv/YC3ZPKUKVNYTlrOO7ZO6YFKE/ak3J5TeYHPU=
+github.com/mittwald/go-helm-client v0.12.18/go.mod h1:dLl5NkdKCvwKvLIdZzg4MDbxhSKmuimdmM3WpsAzS0I=
+github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
+github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
+github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU=
+github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=
+github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
+github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs=
+github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
+github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
+github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
+github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
+github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
+github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
+github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
+github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
+github.com/oleiade/lane/v2 v2.0.0 h1:XW/ex/Inr+bPkLd3O240xrFOhUkTd4Wy176+Gv0E3Qw=
+github.com/oleiade/lane/v2 v2.0.0/go.mod h1:i5FBPFAYSWCgLh58UkUGCChjcCzef/MI7PlQm2TKCeg=
+github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus=
+github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8=
+github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y=
+github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
+github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
+github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
+github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
+github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
+github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
+github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
+github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
+github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
+github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c h1:dAMKvw0MlJT1GshSTtih8C2gDs04w8dReiOGXrGLNoY=
+github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
+github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
+github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY=
+github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg=
+github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.80.1 h1:DP+PUNVOc+Bkft8a4QunLzaZ0RspWuD3tBbcPHr2PeE=
+github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.80.1/go.mod h1:6x4x0t9BP35g4XcjkHE9EB3RxhyfxpdpmZKd/Qyk8+M=
+github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
+github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
+github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
+github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
+github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE=
+github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
+github.com/prometheus/procfs v0.16.0 h1:xh6oHhKwnOJKMYiYBDWmkHqQPyiY40sny36Cmx2bbsM=
+github.com/prometheus/procfs v0.16.0/go.mod h1:8veyXUu3nGP7oaCxhX6yeaM5u4stL2FeMXnCqhDthZg=
+github.com/prometheus/prom2json v1.4.1 h1:7McxdrHgPEOtMwWjkKtd0v5AhpR2Q6QAnlHKVxq0+tQ=
+github.com/prometheus/prom2json v1.4.1/go.mod h1:CzOQykSKFxXuC7ELUZHOHQvwKesQ3eN0p2PWLhFitQM=
+github.com/prometheus/prometheus v0.302.1 h1:xqVdrwrB4WNpdgJqxsz5loqFWNUZitsK8myqLuSZ6Ag=
+github.com/prometheus/prometheus v0.302.1/go.mod h1:YcyCoTbUR/TM8rY3Aoeqr0AWTu/pu1Ehh+trpX3eRzg=
+github.com/redis/go-redis/extra/rediscmd/v9 v9.0.5 h1:EaDatTxkdHG+U3Bk4EUr+DZ7fOGwTfezUiUJMaIcaho=
+github.com/redis/go-redis/extra/rediscmd/v9 v9.0.5/go.mod h1:fyalQWdtzDBECAQFBJuQe5bzQ02jGd5Qcbgb97Flm7U=
+github.com/redis/go-redis/extra/redisotel/v9 v9.0.5 h1:EfpWLLCyXw8PSM2/XNJLjI3Pb27yVE+gIAfeqp8LUCc=
+github.com/redis/go-redis/extra/redisotel/v9 v9.0.5/go.mod h1:WZjPDy7VNzn77AAfnAfVjZNvfJTYfPetfZk5yoSTLaQ=
+github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM=
+github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
+github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
+github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
+github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
+github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
+github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
+github.com/rubenv/sql-migrate v1.8.0 h1:dXnYiJk9k3wetp7GfQbKJcPHjVJL6YK19tKj8t2Ns0o=
+github.com/rubenv/sql-migrate v1.8.0/go.mod h1:F2bGFBwCU+pnmbtNYDeKvSuvL6lBVtXDXUUv5t+u1qw=
+github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
+github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/safchain/ethtool v0.5.10 h1:Im294gZtuf4pSGJRAOGKaASNi3wMeFaGaWuSaomedpc=
+github.com/safchain/ethtool v0.5.10/go.mod h1:w9jh2Lx7YBR4UwzLkzCmWl85UY0W2uZdd7/DckVE5+c=
+github.com/secure-io/sio-go v0.3.1 h1:dNvY9awjabXTYGsTF1PiCySl9Ltofk9GA3VdWlo7rRc=
+github.com/secure-io/sio-go v0.3.1/go.mod h1:+xbkjDzPjwh4Axd07pRKSNriS9SCiYksWnZqdnfpQxs=
+github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
+github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
+github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
+github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
+github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
+github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
+github.com/shoenig/test v1.11.0 h1:NoPa5GIoBwuqzIviCrnUJa+t5Xb4xi5Z+zODJnIDsEQ=
+github.com/shoenig/test v1.11.0/go.mod h1:UxJ6u/x2v/TNs/LoLxBNJRV9DiwBBKYxXSyczsBHFoI=
+github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
+github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
+github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
+github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
+github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
+github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
+github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
+github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
+github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
+github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
+github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
+github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/thoas/go-funk v0.9.3 h1:7+nAEx3kn5ZJcnDm2Bh23N2yOtweO14bi//dvRtgLpw=
+github.com/thoas/go-funk v0.9.3/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q=
+github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
+github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
+github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
+github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
+github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
+github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
+github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
+github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
+github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
+github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
+github.com/tinylib/msgp v1.2.5 h1:WeQg1whrXRFiZusidTQqzETkRpGjFjcIhW6uqWH09po=
+github.com/tinylib/msgp v1.2.5/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0=
+github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4=
+github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4=
+github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso=
+github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ=
+github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
+github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
+github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
+github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
+github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
+github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
+github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
+github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ=
+github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
+github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
+go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
+go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
+go.opentelemetry.io/contrib/bridges/prometheus v0.57.0 h1:UW0+QyeyBVhn+COBec3nGhfnFe5lwB0ic1JBVjzhk0w=
+go.opentelemetry.io/contrib/bridges/prometheus v0.57.0/go.mod h1:ppciCHRLsyCio54qbzQv0E4Jyth/fLWDTJYfvWpcSVk=
+go.opentelemetry.io/contrib/exporters/autoexport v0.57.0 h1:jmTVJ86dP60C01K3slFQa2NQ/Aoi7zA+wy7vMOKD9H4=
+go.opentelemetry.io/contrib/exporters/autoexport v0.57.0/go.mod h1:EJBheUMttD/lABFyLXhce47Wr6DPWYReCzaZiXadH7g=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
+go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
+go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
+go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.8.0 h1:WzNab7hOOLzdDF/EoWCt4glhrbMPVMOO5JYTmpz36Ls=
+go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.8.0/go.mod h1:hKvJwTzJdp90Vh7p6q/9PAOd55dI6WA6sWj62a/JvSs=
+go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.8.0 h1:S+LdBGiQXtJdowoJoQPEtI52syEP/JYBUpjO49EQhV8=
+go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.8.0/go.mod h1:5KXybFvPGds3QinJWQT7pmXf+TN5YIa7CNYObWRkj50=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.32.0 h1:j7ZSD+5yn+lo3sGV69nW04rRR0jhYnBwjuX3r0HvnK0=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.32.0/go.mod h1:WXbYJTUaZXAbYd8lbgGuvih0yuCfOFC5RJoYnoLcGz8=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.32.0 h1:t/Qur3vKSkUCcDVaSumWF2PKHt85pc7fRvFuoVT8qFU=
+go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.32.0/go.mod h1:Rl61tySSdcOJWoEgYZVtmnKdA0GeKrSqkHC1t+91CH8=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0 h1:dNzwXjZKpMpE2JhmO+9HsPl42NIXFIFSUSSs0fiqra0=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0/go.mod h1:90PoxvaEB5n6AOdZvi+yWJQoE95U8Dhhw2bSyRqnTD0=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 h1:tgJ0uaNS4c98WRNUEx5U3aDlrDOI5Rs+1Vifcw4DJ8U=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0/go.mod h1:U7HYyW0zt/a9x5J1Kjs+r1f/d4ZHnYFclhYY2+YbeoE=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0 h1:BEj3SPM81McUZHYjRS5pEgNgnmzGJ5tRpU5krWnV8Bs=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0/go.mod h1:9cKLGBDzI/F3NoHLQGm4ZrYdIHsvGt6ej6hUowxY0J4=
+go.opentelemetry.io/otel/exporters/prometheus v0.54.0 h1:rFwzp68QMgtzu9PgP3jm9XaMICI6TsofWWPcBDKwlsU=
+go.opentelemetry.io/otel/exporters/prometheus v0.54.0/go.mod h1:QyjcV9qDP6VeK5qPyKETvNjmaaEc7+gqjh4SS0ZYzDU=
+go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.8.0 h1:CHXNXwfKWfzS65yrlB2PVds1IBZcdsX8Vepy9of0iRU=
+go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.8.0/go.mod h1:zKU4zUgKiaRxrdovSS2amdM5gOc59slmo/zJwGX+YBg=
+go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.32.0 h1:SZmDnHcgp3zwlPBS2JX2urGYe/jBKEIT6ZedHRUyCz8=
+go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.32.0/go.mod h1:fdWW0HtZJ7+jNpTKUR0GpMEDP69nR8YBJQxNiVCE3jk=
+go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.32.0 h1:cC2yDI3IQd0Udsux7Qmq8ToKAx1XCilTQECZ0KDZyTw=
+go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.32.0/go.mod h1:2PD5Ex6z8CFzDbTdOlwyNIUywRr1DN0ospafJM1wJ+s=
+go.opentelemetry.io/otel/log v0.8.0 h1:egZ8vV5atrUWUbnSsHn6vB8R21G2wrKqNiDt3iWertk=
+go.opentelemetry.io/otel/log v0.8.0/go.mod h1:M9qvDdUTRCopJcGRKg57+JSQ9LgLBrwwfC32epk5NX8=
+go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
+go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
+go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
+go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
+go.opentelemetry.io/otel/sdk/log v0.8.0 h1:zg7GUYXqxk1jnGF/dTdLPrK06xJdrXgqgFLnI4Crxvs=
+go.opentelemetry.io/otel/sdk/log v0.8.0/go.mod h1:50iXr0UVwQrYS45KbruFrEt4LvAdCaWWgIrsN3ZQggo=
+go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
+go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
+go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
+go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
+go.opentelemetry.io/proto/otlp v1.7.0 h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os=
+go.opentelemetry.io/proto/otlp v1.7.0/go.mod h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo=
+go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
+go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
+go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
+go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
+go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
+go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
+go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
+go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
+golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
+golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
+golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
+golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
+golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
+golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
+golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
+golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
+golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
+golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
+golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
+golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
+golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
+golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
+golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
+golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw=
+gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
+google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ=
+google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a h1:SGktgSolFCo75dnHJF2yMvnns6jCmHFJ0vE4Vn2JKvQ=
+google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a/go.mod h1:a77HrdMjoeKbnd2jmgcWdaS++ZLZAEq3orIOAEIKiVw=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
+google.golang.org/grpc v1.72.2 h1:TdbGzwb82ty4OusHWepvFWGLgIbNo1/SUynEN0ssqv8=
+google.golang.org/grpc v1.72.2/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
+google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
+google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=
+gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
+gopkg.in/h2non/gock.v1 v1.1.2 h1:jBbHXgGBK/AoPVfJh5x4r/WxIrElvbLel8TCZkkZJoY=
+gopkg.in/h2non/gock.v1 v1.1.2/go.mod h1:n7UGz/ckNChHiK05rDoiC4MYSunEC/lyaUm2WWaDva0=
+gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
+gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o=
+gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g=
+helm.sh/helm/v3 v3.18.4 h1:pNhnHM3nAmDrxz6/UC+hfjDY4yeDATQCka2/87hkZXQ=
+helm.sh/helm/v3 v3.18.4/go.mod h1:WVnwKARAw01iEdjpEkP7Ii1tT1pTPYfM1HsakFKM3LI=
+k8s.io/api v0.33.2 h1:YgwIS5jKfA+BZg//OQhkJNIfie/kmRsO0BmNaVSimvY=
+k8s.io/api v0.33.2/go.mod h1:fhrbphQJSM2cXzCWgqU29xLDuks4mu7ti9vveEnpSXs=
+k8s.io/apiextensions-apiserver v0.33.2 h1:6gnkIbngnaUflR3XwE1mCefN3YS8yTD631JXQhsU6M8=
+k8s.io/apiextensions-apiserver v0.33.2/go.mod h1:IvVanieYsEHJImTKXGP6XCOjTwv2LUMos0YWc9O+QP8=
+k8s.io/apimachinery v0.33.2 h1:IHFVhqg59mb8PJWTLi8m1mAoepkUNYmptHsV+Z1m5jY=
+k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
+k8s.io/apiserver v0.33.2 h1:KGTRbxn2wJagJowo29kKBp4TchpO1DRO3g+dB/KOJN4=
+k8s.io/apiserver v0.33.2/go.mod h1:9qday04wEAMLPWWo9AwqCZSiIn3OYSZacDyu/AcoM/M=
+k8s.io/cli-runtime v0.33.2 h1:koNYQKSDdq5AExa/RDudXMhhtFasEg48KLS2KSAU74Y=
+k8s.io/cli-runtime v0.33.2/go.mod h1:gnhsAWpovqf1Zj5YRRBBU7PFsRc6NkEkwYNQE+mXL88=
+k8s.io/client-go v0.33.2 h1:z8CIcc0P581x/J1ZYf4CNzRKxRvQAwoAolYPbtQes+E=
+k8s.io/client-go v0.33.2/go.mod h1:9mCgT4wROvL948w6f6ArJNb7yQd7QsvqavDeZHvNmHo=
+k8s.io/component-base v0.33.2 h1:sCCsn9s/dG3ZrQTX/Us0/Sx2R0G5kwa0wbZFYoVp/+0=
+k8s.io/component-base v0.33.2/go.mod h1:/41uw9wKzuelhN+u+/C59ixxf4tYQKW7p32ddkYNe2k=
+k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
+k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
+k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4=
+k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8=
+k8s.io/kubectl v0.33.2 h1:7XKZ6DYCklu5MZQzJe+CkCjoGZwD1wWl7t/FxzhMz7Y=
+k8s.io/kubectl v0.33.2/go.mod h1:8rC67FB8tVTYraovAGNi/idWIK90z2CHFNMmGJZJ3KI=
+k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979 h1:jgJW5IePPXLGB8e/1wvd0Ich9QE97RvvF3a8J3fP/Lg=
+k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
+oras.land/oras-go/v2 v2.6.0 h1:X4ELRsiGkrbeox69+9tzTu492FMUu7zJQW6eJU+I2oc=
+oras.land/oras-go/v2 v2.6.0/go.mod h1:magiQDfG6H1O9APp+rOsvCPcW1GD2MM7vgnKY0Y+u1o=
+sigs.k8s.io/controller-runtime v0.21.0 h1:CYfjpEuicjUecRk+KAeyYh+ouUBn4llGyDYytIGcJS8=
+sigs.k8s.io/controller-runtime v0.21.0/go.mod h1:OSg14+F65eWqIu4DceX7k/+QRAbTTvxeQSNSOQpukWM=
+sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=
+sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
+sigs.k8s.io/kustomize/api v0.19.0 h1:F+2HB2mU1MSiR9Hp1NEgoU2q9ItNOaBJl0I4Dlus5SQ=
+sigs.k8s.io/kustomize/api v0.19.0/go.mod h1:/BbwnivGVcBh1r+8m3tH1VNxJmHSk1PzP5fkP6lbL1o=
+sigs.k8s.io/kustomize/kyaml v0.19.0 h1:RFge5qsO1uHhwJsu3ipV7RNolC7Uozc0jUBC/61XSlA=
+sigs.k8s.io/kustomize/kyaml v0.19.0/go.mod h1:FeKD5jEOH+FbZPpqUghBP8mrLjJ3+zD3/rf9NNu1cwY=
+sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
+sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
+sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
+sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc=
+sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps=
+sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
+sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
diff --git a/complement/tests/federation_test.go b/complement/tests/federation_test.go
new file mode 100644
index 0000000000..d423792a72
--- /dev/null
+++ b/complement/tests/federation_test.go
@@ -0,0 +1,65 @@
+// This file is licensed under the Affero General Public License (AGPL) version 3.
+//
+// Copyright (C) 2026 Element Creations Ltd
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// See the GNU Affero General Public License for more details:
+// .
+
+package synapse_tests
+
+import (
+ "testing"
+
+ "github.com/matrix-org/complement"
+ "github.com/matrix-org/complement/client"
+ "github.com/matrix-org/complement/helpers"
+ "github.com/matrix-org/gomatrixserverlib/spec"
+)
+
+// Stub test to ensure that homeservers can communicate with each other (federation works correctly).
+//
+// TODO: This test will disappear once we have other real Synapse specific tests in
+// place. This is simply here as an example without bloating the PR with some specific
+// new tests.
+func TestFederation(t *testing.T) {
+ // Create two homeservers
+ deployment := complement.Deploy(t, 2)
+ defer deployment.Destroy(t)
+
+ alice := deployment.Register(t, "hs1", helpers.RegistrationOpts{})
+ bob := deployment.Register(t, "hs2", helpers.RegistrationOpts{})
+
+ aliceRoomID := alice.MustCreateRoom(t, map[string]any{
+ "preset": "public_chat",
+ })
+ bobRoomID := bob.MustCreateRoom(t, map[string]any{
+ "preset": "public_chat",
+ })
+
+ t.Run("parallel", func(t *testing.T) {
+ t.Run("HS1 -> HS2", func(t *testing.T) {
+ t.Parallel()
+
+ alice.MustJoinRoom(t, bobRoomID, []spec.ServerName{
+ deployment.GetFullyQualifiedHomeserverName(t, "hs2"),
+ })
+
+ bob.MustSyncUntil(t, client.SyncReq{}, client.SyncJoinedTo(alice.UserID, bobRoomID))
+ })
+
+ t.Run("HS2 -> HS1", func(t *testing.T) {
+ t.Parallel()
+
+ bob.MustJoinRoom(t, aliceRoomID, []spec.ServerName{
+ deployment.GetFullyQualifiedHomeserverName(t, "hs1"),
+ })
+
+ alice.MustSyncUntil(t, client.SyncReq{}, client.SyncJoinedTo(bob.UserID, aliceRoomID))
+ })
+ })
+}
diff --git a/complement/tests/main_test.go b/complement/tests/main_test.go
new file mode 100644
index 0000000000..1d62900d38
--- /dev/null
+++ b/complement/tests/main_test.go
@@ -0,0 +1,23 @@
+// This file is licensed under the Affero General Public License (AGPL) version 3.
+//
+// Copyright (C) 2026 Element Creations Ltd
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// See the GNU Affero General Public License for more details:
+// .
+
+package synapse_tests
+
+import (
+ "testing"
+
+ "github.com/matrix-org/complement"
+)
+
+func TestMain(m *testing.M) {
+ complement.TestMain(m, "synapse")
+}
diff --git a/scripts-dev/complement.sh b/scripts-dev/complement.sh
index 2447e0dc7b..dc2262a2a3 100755
--- a/scripts-dev/complement.sh
+++ b/scripts-dev/complement.sh
@@ -47,6 +47,9 @@ usage() {
cat >&2 <...
Run the complement test suite on Synapse.
+ --in-repo
+ Whether to run the in-repo suite of Complement tests (see `./complement` in this project)
+ vs the Complement tests from the Complement repo.
-f, --fast
Skip rebuilding the docker images, and just use the most recent
@@ -82,6 +85,7 @@ main() {
# parse our arguments
skip_docker_build=""
skip_complement_run=""
+ use_in_repo_tests=""
while [ $# -ge 1 ]; do
arg=$1
case "$arg" in
@@ -89,6 +93,9 @@ main() {
usage
return 1
;;
+ "--in-repo")
+ use_in_repo_tests=1
+ ;;
"-f"|"--fast")
skip_docker_build=1
;;
@@ -216,7 +223,10 @@ main() {
echo "Skipping Docker image build as requested."
fi
- test_packages=(
+ # Default set of Complement tests to run from the Complement repo
+ #
+ # We pick and choose the specific MSC's that Synapse supports.
+ default_complement_test_packages=(
./tests/csapi
./tests
./tests/msc3874
@@ -233,7 +243,15 @@ main() {
# Export the list of test packages as a space-separated environment variable, so other
# scripts can use it.
- export SYNAPSE_SUPPORTED_COMPLEMENT_TEST_PACKAGES="${test_packages[@]}"
+ export SYNAPSE_SUPPORTED_COMPLEMENT_TEST_PACKAGES="${default_complement_test_packages[@]}"
+
+ # Default set of Complement tests to run when using the in-repo test suite. Most
+ # likely, this should be all tests.
+ #
+ # Relative to the `./complement` repo in this project
+ default_in_repo_complement_test_packages=(
+ ./tests/...
+ )
export COMPLEMENT_BASE_IMAGE=complement-synapse
if [ -n "$use_editable_synapse" ]; then
@@ -316,11 +334,26 @@ main() {
echo "Skipping Complement run as requested."
return 0
fi
+
+ # Print out the executed commands so it's more obvious what's happening at the end here.
+ # Things are slightly ambiguous with the in-repo vs Complement tests.
+ set -x
- # Run the tests!
- echo "Running Complement with ${test_args[@]} $@ ${test_packages[@]}"
- cd "$COMPLEMENT_DIR"
- go test "${test_args[@]}" "$@" "${test_packages[@]}"
+ if [ -n "$use_in_repo_tests" ]; then
+ # Run the suite of Complement tests in the `./complement` directory in this repo
+ cd "./complement"
+ go test "${test_args[@]}" "$@" "${default_in_repo_complement_test_packages[@]}"
+ else
+ # Run the tests (from the Complement repo)!
+ cd "$COMPLEMENT_DIR"
+ go test "${test_args[@]}" "$@" "${default_complement_test_packages[@]}"
+ fi
+
+ # We don't need to print out executed commands anymore
+ #
+ # This is just `set +x` without printing `+ set +x` to the console (via
+ # https://stackoverflow.com/questions/13195655/bash-set-x-without-it-being-printed/19226038#19226038)
+ { set +x; } 2>/dev/null
}
main "$@"
diff --git a/scripts-dev/lint.sh b/scripts-dev/lint.sh
index d5e10d4292..b10cf8b80a 100755
--- a/scripts-dev/lint.sh
+++ b/scripts-dev/lint.sh
@@ -139,3 +139,14 @@ mypy
# Generate configuration documentation from the JSON Schema
./scripts-dev/gen_config_documentation.py schema/synapse-config.schema.yaml > docs/usage/configuration/config_documentation.md
+
+# Lint/format the in-repo Complement test code (Go)
+pushd ./complement
+# Run golangci-lint with:
+# - The `run` command will lint the code
+# - `--fix`: Will apply any suggested fixes like autofixes from `linters` *and*
+# `formatters` which always produce suggested fixes that are equivalent to running
+# `golangci-lint fmt`.
+# - `--max-issues-per-linter=0`: Show all issues, don't limit the number reported
+go run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.6.1 run ./... --fix --max-issues-per-linter=0
+popd
From 52fb6e98acf8c41662d070c0803a310f7f27bc7b Mon Sep 17 00:00:00 2001
From: Olivier 'reivilibre
Date: Wed, 11 Feb 2026 12:41:38 +0000
Subject: [PATCH 05/19] Support sending and receiving MSC4354 Sticky Event
metadata. (#19365)
Part of: MSC4354 whose experimental feature tracking issue is
https://github.com/element-hq/synapse/issues/19409
Follows: #19340 (a necessary bugfix for `/event/` to set this metadata)
Partially supersedes: #18968
This PR implements the first batch of work to support MSC4354 Sticky
Events.
Sticky events are events that have been configured with a finite
'stickiness' duration,
capped to 1 hour per current MSC draft.
Whilst an event is sticky, we provide stronger delivery guarantees for
the event, both to
our clients and to remote homeservers, essentially making it reliable
delivery as long as we
have a functional connection to the client/server and until the
stickiness expires.
This PR merely supports creating sticky events and receiving the sticky
TTL metadata in clients.
It is not suitable for trialling sticky events since none of the other
semantics are implemented.
Contains a temporary SQLite workaround due to a bug in our supported
version enforcement: https://github.com/element-hq/synapse/issues/19452
---------
Signed-off-by: Olivier 'reivilibre
Co-authored-by: Eric Eastwood
---
changelog.d/19365.feature | 1 +
.../conf/workers-shared-extra.yaml.j2 | 2 +
synapse/api/constants.py | 43 ++-
synapse/app/generic_worker.py | 2 +
synapse/config/experimental.py | 6 +
synapse/config/workers.py | 4 +-
synapse/events/__init__.py | 30 +-
synapse/events/builder.py | 10 +-
synapse/handlers/delayed_events.py | 13 +-
synapse/notifier.py | 1 +
synapse/replication/tcp/client.py | 11 +-
synapse/replication/tcp/handler.py | 7 +
synapse/replication/tcp/streams/__init__.py | 3 +
synapse/replication/tcp/streams/_base.py | 45 +++
synapse/rest/client/room.py | 29 +-
synapse/rest/client/versions.py | 2 +
synapse/storage/databases/main/__init__.py | 2 +
.../storage/databases/main/delayed_events.py | 9 +-
synapse/storage/databases/main/events.py | 11 +
.../storage/databases/main/sticky_events.py | 322 ++++++++++++++++++
.../schema/main/delta/93/01_sticky_events.sql | 60 ++++
.../93/01_sticky_events_seq.sql.postgres | 18 +
synapse/streams/events.py | 3 +
synapse/types/__init__.py | 10 +-
synapse/visibility.py | 14 +
tests/rest/admin/test_room.py | 4 +-
tests/rest/client/test_rooms.py | 4 +-
tests/rest/client/test_sticky_events.py | 179 ++++++++++
tests/rest/client/utils.py | 39 +++
tests/storage/test_sticky_events.py | 278 +++++++++++++++
30 files changed, 1147 insertions(+), 15 deletions(-)
create mode 100644 changelog.d/19365.feature
create mode 100644 synapse/storage/databases/main/sticky_events.py
create mode 100644 synapse/storage/schema/main/delta/93/01_sticky_events.sql
create mode 100644 synapse/storage/schema/main/delta/93/01_sticky_events_seq.sql.postgres
create mode 100644 tests/rest/client/test_sticky_events.py
create mode 100644 tests/storage/test_sticky_events.py
diff --git a/changelog.d/19365.feature b/changelog.d/19365.feature
new file mode 100644
index 0000000000..c35afdc179
--- /dev/null
+++ b/changelog.d/19365.feature
@@ -0,0 +1 @@
+Support sending and receiving [MSC4354 Sticky Event](https://github.com/matrix-org/matrix-spec-proposals/pull/4354) metadata.
\ No newline at end of file
diff --git a/docker/complement/conf/workers-shared-extra.yaml.j2 b/docker/complement/conf/workers-shared-extra.yaml.j2
index 101ff153a5..120b3b9496 100644
--- a/docker/complement/conf/workers-shared-extra.yaml.j2
+++ b/docker/complement/conf/workers-shared-extra.yaml.j2
@@ -139,6 +139,8 @@ experimental_features:
msc4155_enabled: true
# Thread Subscriptions
msc4306_enabled: true
+ # Sticky Events
+ msc4354_enabled: true
server_notices:
system_mxid_localpart: _server
diff --git a/synapse/api/constants.py b/synapse/api/constants.py
index 9b6a68e929..b8ef5dac50 100644
--- a/synapse/api/constants.py
+++ b/synapse/api/constants.py
@@ -24,7 +24,9 @@
"""Contains constants from the specification."""
import enum
-from typing import Final
+from typing import Final, TypedDict
+
+from synapse.util.duration import Duration
# the max size of a (canonical-json-encoded) event
MAX_PDU_SIZE = 65536
@@ -292,6 +294,8 @@ class EventUnsignedContentFields:
# Requesting user's membership, per MSC4115
MEMBERSHIP: Final = "membership"
+ STICKY_TTL: Final = "msc4354_sticky_duration_ttl_ms"
+
class MTextFields:
"""Fields found inside m.text content blocks."""
@@ -377,3 +381,40 @@ class Direction(enum.Enum):
class ProfileFields:
DISPLAYNAME: Final = "displayname"
AVATAR_URL: Final = "avatar_url"
+
+
+class StickyEventField(TypedDict):
+ """
+ Dict content of the `sticky` part of an event.
+ """
+
+ duration_ms: int
+
+
+class StickyEvent:
+ QUERY_PARAM_NAME: Final = "org.matrix.msc4354.sticky_duration_ms"
+ """
+ Query parameter used by clients for setting the sticky duration of an event they are sending.
+
+ Applies to:
+ - /rooms/.../send/...
+ - /rooms/.../state/...
+ """
+
+ EVENT_FIELD_NAME: Final = "msc4354_sticky"
+ """
+ Name of the field in the top-level event dict that contains the sticky event dict.
+ """
+
+ MAX_DURATION: Duration = Duration(hours=1)
+ """
+ Maximum stickiness duration as specified in MSC4354.
+ Ensures that data in the /sync response can go down and not grow unbounded.
+ """
+
+ MAX_EVENTS_IN_SYNC: Final = 100
+ """
+ Maximum number of sticky events to include in /sync.
+
+ This is the default specified in the MSC. Chosen arbitrarily.
+ """
diff --git a/synapse/app/generic_worker.py b/synapse/app/generic_worker.py
index 0a4abd1839..159cd44237 100644
--- a/synapse/app/generic_worker.py
+++ b/synapse/app/generic_worker.py
@@ -102,6 +102,7 @@
from synapse.storage.databases.main.sliding_sync import SlidingSyncStore
from synapse.storage.databases.main.state import StateGroupWorkerStore
from synapse.storage.databases.main.stats import StatsStore
+from synapse.storage.databases.main.sticky_events import StickyEventsWorkerStore
from synapse.storage.databases.main.stream import StreamWorkerStore
from synapse.storage.databases.main.tags import TagsWorkerStore
from synapse.storage.databases.main.task_scheduler import TaskSchedulerWorkerStore
@@ -137,6 +138,7 @@ class GenericWorkerStore(
RoomWorkerStore,
DirectoryWorkerStore,
ThreadSubscriptionsWorkerStore,
+ StickyEventsWorkerStore,
PushRulesWorkerStore,
ApplicationServiceTransactionWorkerStore,
ApplicationServiceWorkerStore,
diff --git a/synapse/config/experimental.py b/synapse/config/experimental.py
index 9b6ff482cf..b6c8b8c062 100644
--- a/synapse/config/experimental.py
+++ b/synapse/config/experimental.py
@@ -580,5 +580,11 @@ def read_config(
# (and MSC4308: Thread Subscriptions extension to Sliding Sync)
self.msc4306_enabled: bool = experimental.get("msc4306_enabled", False)
+ # MSC4354: Sticky Events
+ # Tracked in: https://github.com/element-hq/synapse/issues/19409
+ # Note that sticky events persisted before this feature is enabled will not be
+ # considered sticky by the local homeserver.
+ self.msc4354_enabled: bool = experimental.get("msc4354_enabled", False)
+
# MSC4380: Invite blocking
self.msc4380_enabled: bool = experimental.get("msc4380_enabled", False)
diff --git a/synapse/config/workers.py b/synapse/config/workers.py
index ec8ab9506b..996be88cb2 100644
--- a/synapse/config/workers.py
+++ b/synapse/config/workers.py
@@ -127,7 +127,9 @@ class WriterLocations:
"""Specifies the instances that write various streams.
Attributes:
- events: The instances that write to the event and backfill streams.
+ events: The instances that write to the event, backfill and `sticky_events` streams.
+ (`sticky_events` is written to during event persistence so must be handled by the
+ same stream writers.)
typing: The instances that write to the typing stream. Currently
can only be a single instance.
to_device: The instances that write to the to_device stream. Currently
diff --git a/synapse/events/__init__.py b/synapse/events/__init__.py
index c7eaf7eda2..e6162997dd 100644
--- a/synapse/events/__init__.py
+++ b/synapse/events/__init__.py
@@ -36,7 +36,12 @@
import attr
from unpaddedbase64 import encode_base64
-from synapse.api.constants import EventContentFields, EventTypes, RelationTypes
+from synapse.api.constants import (
+ EventContentFields,
+ EventTypes,
+ RelationTypes,
+ StickyEvent,
+)
from synapse.api.room_versions import EventFormatVersions, RoomVersion, RoomVersions
from synapse.synapse_rust.events import EventInternalMetadata
from synapse.types import (
@@ -44,6 +49,7 @@
StrCollection,
)
from synapse.util.caches import intern_dict
+from synapse.util.duration import Duration
from synapse.util.frozenutils import freeze
if TYPE_CHECKING:
@@ -318,6 +324,28 @@ def freeze(self) -> None:
# this will be a no-op if the event dict is already frozen.
self._dict = freeze(self._dict)
+ def sticky_duration(self) -> Duration | None:
+ """
+ Returns the effective sticky duration of this event, or None
+ if the event does not have a sticky duration.
+ (Sticky Events are a MSC4354 feature.)
+
+ Clamps the sticky duration to the maximum allowed duration.
+ """
+ sticky_obj = self.get_dict().get(StickyEvent.EVENT_FIELD_NAME, None)
+ if type(sticky_obj) is not dict:
+ return None
+ sticky_duration_ms = sticky_obj.get("duration_ms", None)
+ # MSC: Clamp to 0 and MAX_DURATION (1 hour)
+ # We use `type(...) is int` to avoid accepting bools as `isinstance(True, int)`
+ # (bool is a subclass of int)
+ if type(sticky_duration_ms) is int and sticky_duration_ms >= 0:
+ return min(
+ Duration(milliseconds=sticky_duration_ms),
+ StickyEvent.MAX_DURATION,
+ )
+ return None
+
def __str__(self) -> str:
return self.__repr__()
diff --git a/synapse/events/builder.py b/synapse/events/builder.py
index 6a2812109d..2cd1bf6106 100644
--- a/synapse/events/builder.py
+++ b/synapse/events/builder.py
@@ -24,7 +24,7 @@
import attr
from signedjson.types import SigningKey
-from synapse.api.constants import MAX_DEPTH, EventTypes
+from synapse.api.constants import MAX_DEPTH, EventTypes, StickyEvent, StickyEventField
from synapse.api.room_versions import (
KNOWN_EVENT_FORMAT_VERSIONS,
EventFormatVersions,
@@ -89,6 +89,10 @@ class EventBuilder:
content: JsonDict = attr.Factory(dict)
unsigned: JsonDict = attr.Factory(dict)
+ sticky: StickyEventField | None = None
+ """
+ Fields for MSC4354: Sticky Events
+ """
# These only exist on a subset of events, so they raise AttributeError if
# someone tries to get them when they don't exist.
@@ -269,6 +273,9 @@ async def build(
if self._origin_server_ts is not None:
event_dict["origin_server_ts"] = self._origin_server_ts
+ if self.sticky is not None:
+ event_dict[StickyEvent.EVENT_FIELD_NAME] = self.sticky
+
return create_local_event_from_event_dict(
clock=self._clock,
hostname=self._hostname,
@@ -318,6 +325,7 @@ def for_room_version(
unsigned=key_values.get("unsigned", {}),
redacts=key_values.get("redacts", None),
origin_server_ts=key_values.get("origin_server_ts", None),
+ sticky=key_values.get(StickyEvent.EVENT_FIELD_NAME, None),
)
diff --git a/synapse/handlers/delayed_events.py b/synapse/handlers/delayed_events.py
index c58d1d42bc..7e41716f1e 100644
--- a/synapse/handlers/delayed_events.py
+++ b/synapse/handlers/delayed_events.py
@@ -17,7 +17,7 @@
from twisted.internet.interfaces import IDelayedCall
-from synapse.api.constants import EventTypes
+from synapse.api.constants import EventTypes, StickyEvent, StickyEventField
from synapse.api.errors import ShadowBanError, SynapseError
from synapse.api.ratelimiting import Ratelimiter
from synapse.config.workers import MAIN_PROCESS_INSTANCE_NAME
@@ -333,6 +333,7 @@ async def add(
origin_server_ts: int | None,
content: JsonDict,
delay: int,
+ sticky_duration_ms: int | None,
) -> str:
"""
Creates a new delayed event and schedules its delivery.
@@ -346,7 +347,9 @@ async def add(
If None, the timestamp will be the actual time when the event is sent.
content: The content of the event to be sent.
delay: How long (in milliseconds) to wait before automatically sending the event.
-
+ sticky_duration_ms: If an MSC4354 sticky event: the sticky duration (in milliseconds).
+ The event will be attempted to be reliably delivered to clients and remote servers
+ during its sticky period.
Returns: The ID of the added delayed event.
Raises:
@@ -382,6 +385,7 @@ async def add(
origin_server_ts=origin_server_ts,
content=content,
delay=delay,
+ sticky_duration_ms=sticky_duration_ms,
)
if self._repl_client is not None:
@@ -570,7 +574,10 @@ async def _send_event(
if event.state_key is not None:
event_dict["state_key"] = event.state_key
-
+ if event.sticky_duration_ms is not None:
+ event_dict[StickyEvent.EVENT_FIELD_NAME] = StickyEventField(
+ duration_ms=event.sticky_duration_ms
+ )
(
sent_event,
_,
diff --git a/synapse/notifier.py b/synapse/notifier.py
index cf3923110e..93d438def7 100644
--- a/synapse/notifier.py
+++ b/synapse/notifier.py
@@ -526,6 +526,7 @@ def on_new_event(
StreamKeyType.TYPING,
StreamKeyType.UN_PARTIAL_STATED_ROOMS,
StreamKeyType.THREAD_SUBSCRIPTIONS,
+ StreamKeyType.STICKY_EVENTS,
],
new_token: int,
users: Collection[str | UserID] | None = None,
diff --git a/synapse/replication/tcp/client.py b/synapse/replication/tcp/client.py
index fdda932ead..bc7e46d4c9 100644
--- a/synapse/replication/tcp/client.py
+++ b/synapse/replication/tcp/client.py
@@ -43,7 +43,10 @@
UnPartialStatedEventStream,
UnPartialStatedRoomStream,
)
-from synapse.replication.tcp.streams._base import ThreadSubscriptionsStream
+from synapse.replication.tcp.streams._base import (
+ StickyEventsStream,
+ ThreadSubscriptionsStream,
+)
from synapse.replication.tcp.streams.events import (
EventsStream,
EventsStreamEventRow,
@@ -262,6 +265,12 @@ async def on_rdata(
token,
users=[row.user_id for row in rows],
)
+ elif stream_name == StickyEventsStream.NAME:
+ self.notifier.on_new_event(
+ StreamKeyType.STICKY_EVENTS,
+ token,
+ rooms=[row.room_id for row in rows],
+ )
await self._presence_handler.process_replication_rows(
stream_name, instance_name, token, rows
diff --git a/synapse/replication/tcp/handler.py b/synapse/replication/tcp/handler.py
index 087c87545e..ad9fed72dd 100644
--- a/synapse/replication/tcp/handler.py
+++ b/synapse/replication/tcp/handler.py
@@ -67,6 +67,7 @@
)
from synapse.replication.tcp.streams._base import (
DeviceListsStream,
+ StickyEventsStream,
ThreadSubscriptionsStream,
)
from synapse.util.background_queue import BackgroundQueue
@@ -217,6 +218,12 @@ def __init__(self, hs: "HomeServer"):
continue
+ if isinstance(stream, StickyEventsStream):
+ if hs.get_instance_name() in hs.config.worker.writers.events:
+ self._streams_to_replicate.append(stream)
+
+ continue
+
if isinstance(stream, DeviceListsStream):
if hs.get_instance_name() in hs.config.worker.writers.device_lists:
self._streams_to_replicate.append(stream)
diff --git a/synapse/replication/tcp/streams/__init__.py b/synapse/replication/tcp/streams/__init__.py
index 87ac0a5ae1..067847617f 100644
--- a/synapse/replication/tcp/streams/__init__.py
+++ b/synapse/replication/tcp/streams/__init__.py
@@ -40,6 +40,7 @@
PushersStream,
PushRulesStream,
ReceiptsStream,
+ StickyEventsStream,
Stream,
ThreadSubscriptionsStream,
ToDeviceStream,
@@ -68,6 +69,7 @@
ToDeviceStream,
FederationStream,
AccountDataStream,
+ StickyEventsStream,
ThreadSubscriptionsStream,
UnPartialStatedRoomStream,
UnPartialStatedEventStream,
@@ -90,6 +92,7 @@
"ToDeviceStream",
"FederationStream",
"AccountDataStream",
+ "StickyEventsStream",
"ThreadSubscriptionsStream",
"UnPartialStatedRoomStream",
"UnPartialStatedEventStream",
diff --git a/synapse/replication/tcp/streams/_base.py b/synapse/replication/tcp/streams/_base.py
index 4fb2aac202..1ea6b4fa85 100644
--- a/synapse/replication/tcp/streams/_base.py
+++ b/synapse/replication/tcp/streams/_base.py
@@ -763,3 +763,48 @@ async def _update_function(
return [], to_token, False
return rows, rows[-1][0], len(updates) == limit
+
+
+@attr.s(slots=True, auto_attribs=True)
+class StickyEventsStreamRow:
+ """Stream to inform workers about changes to sticky events."""
+
+ room_id: str
+
+ event_id: str
+ """The sticky event ID"""
+
+
+class StickyEventsStream(_StreamFromIdGen):
+ """A sticky event was changed."""
+
+ NAME = "sticky_events"
+ ROW_TYPE = StickyEventsStreamRow
+
+ def __init__(self, hs: "HomeServer"):
+ self.store = hs.get_datastores().main
+ super().__init__(
+ hs.get_instance_name(),
+ self._update_function,
+ self.store._sticky_events_id_gen,
+ )
+
+ async def _update_function(
+ self, instance_name: str, from_token: int, to_token: int, limit: int
+ ) -> StreamUpdateResult:
+ updates = await self.store.get_updated_sticky_events(
+ from_id=from_token, to_id=to_token, limit=limit
+ )
+ rows = [
+ (
+ update.stream_id,
+ # These are the args to `StickyEventsStreamRow`
+ (update.room_id, update.event_id),
+ )
+ for update in updates
+ ]
+
+ if not rows:
+ return [], to_token, False
+
+ return rows, rows[-1][0], len(updates) == limit
diff --git a/synapse/rest/client/room.py b/synapse/rest/client/room.py
index 5e7dcb0191..9172bfcb4e 100644
--- a/synapse/rest/client/room.py
+++ b/synapse/rest/client/room.py
@@ -34,7 +34,13 @@
from twisted.web.server import Request
from synapse import event_auth
-from synapse.api.constants import Direction, EventTypes, Membership
+from synapse.api.constants import (
+ Direction,
+ EventTypes,
+ Membership,
+ StickyEvent,
+ StickyEventField,
+)
from synapse.api.errors import (
AuthError,
Codes,
@@ -210,6 +216,7 @@ def __init__(self, hs: "HomeServer"):
self.clock = hs.get_clock()
self._max_event_delay_ms = hs.config.server.max_event_delay_ms
self._spam_checker_module_callbacks = hs.get_module_api_callbacks().spam_checker
+ self._msc4354_enabled = hs.config.experimental.msc4354_enabled
def register(self, http_server: HttpServer) -> None:
# /rooms/$roomid/state/$eventtype
@@ -331,6 +338,10 @@ async def on_PUT(
if requester.app_service:
origin_server_ts = parse_integer(request, "ts")
+ sticky_duration_ms: int | None = None
+ if self._msc4354_enabled:
+ sticky_duration_ms = parse_integer(request, StickyEvent.QUERY_PARAM_NAME)
+
delay = _parse_request_delay(request, self._max_event_delay_ms)
if delay is not None:
delay_id = await self.delayed_events_handler.add(
@@ -341,6 +352,7 @@ async def on_PUT(
origin_server_ts=origin_server_ts,
content=content,
delay=delay,
+ sticky_duration_ms=sticky_duration_ms,
)
set_tag("delay_id", delay_id)
@@ -368,6 +380,10 @@ async def on_PUT(
"room_id": room_id,
"sender": requester.user.to_string(),
}
+ if sticky_duration_ms is not None:
+ event_dict[StickyEvent.EVENT_FIELD_NAME] = StickyEventField(
+ duration_ms=sticky_duration_ms
+ )
if state_key is not None:
event_dict["state_key"] = state_key
@@ -400,6 +416,7 @@ def __init__(self, hs: "HomeServer"):
self.delayed_events_handler = hs.get_delayed_events_handler()
self.auth = hs.get_auth()
self._max_event_delay_ms = hs.config.server.max_event_delay_ms
+ self._msc4354_enabled = hs.config.experimental.msc4354_enabled
def register(self, http_server: HttpServer) -> None:
# /rooms/$roomid/send/$event_type[/$txn_id]
@@ -420,6 +437,10 @@ async def _do(
if requester.app_service:
origin_server_ts = parse_integer(request, "ts")
+ sticky_duration_ms: int | None = None
+ if self._msc4354_enabled:
+ sticky_duration_ms = parse_integer(request, StickyEvent.QUERY_PARAM_NAME)
+
delay = _parse_request_delay(request, self._max_event_delay_ms)
if delay is not None:
delay_id = await self.delayed_events_handler.add(
@@ -430,6 +451,7 @@ async def _do(
origin_server_ts=origin_server_ts,
content=content,
delay=delay,
+ sticky_duration_ms=sticky_duration_ms,
)
set_tag("delay_id", delay_id)
@@ -446,6 +468,11 @@ async def _do(
if origin_server_ts is not None:
event_dict["origin_server_ts"] = origin_server_ts
+ if sticky_duration_ms is not None:
+ event_dict[StickyEvent.EVENT_FIELD_NAME] = StickyEventField(
+ duration_ms=sticky_duration_ms
+ )
+
try:
(
event,
diff --git a/synapse/rest/client/versions.py b/synapse/rest/client/versions.py
index 75f27c98de..8945849531 100644
--- a/synapse/rest/client/versions.py
+++ b/synapse/rest/client/versions.py
@@ -182,6 +182,8 @@ async def on_GET(self, request: SynapseRequest) -> tuple[int, JsonDict]:
"org.matrix.msc4306": self.config.experimental.msc4306_enabled,
# MSC4169: Backwards-compatible redaction sending using `/send`
"com.beeper.msc4169": self.config.experimental.msc4169_enabled,
+ # MSC4354: Sticky events
+ "org.matrix.msc4354": self.config.experimental.msc4354_enabled,
# MSC4380: Invite blocking
"org.matrix.msc4380": self.config.experimental.msc4380_enabled,
},
diff --git a/synapse/storage/databases/main/__init__.py b/synapse/storage/databases/main/__init__.py
index 12593094f1..9f8d4debbe 100644
--- a/synapse/storage/databases/main/__init__.py
+++ b/synapse/storage/databases/main/__init__.py
@@ -34,6 +34,7 @@
)
from synapse.storage.databases.main.sliding_sync import SlidingSyncStore
from synapse.storage.databases.main.stats import UserSortOrder
+from synapse.storage.databases.main.sticky_events import StickyEventsWorkerStore
from synapse.storage.databases.main.thread_subscriptions import (
ThreadSubscriptionsWorkerStore,
)
@@ -144,6 +145,7 @@ class DataStore(
TagsStore,
AccountDataStore,
ThreadSubscriptionsWorkerStore,
+ StickyEventsWorkerStore,
PushRulesWorkerStore,
StreamWorkerStore,
OpenIdStore,
diff --git a/synapse/storage/databases/main/delayed_events.py b/synapse/storage/databases/main/delayed_events.py
index 5547150515..1727f589e2 100644
--- a/synapse/storage/databases/main/delayed_events.py
+++ b/synapse/storage/databases/main/delayed_events.py
@@ -54,6 +54,7 @@ class EventDetails:
origin_server_ts: Timestamp | None
content: JsonDict
device_id: DeviceID | None
+ sticky_duration_ms: int | None
@attr.s(slots=True, frozen=True, auto_attribs=True)
@@ -122,6 +123,7 @@ async def add_delayed_event(
origin_server_ts: int | None,
content: JsonDict,
delay: int,
+ sticky_duration_ms: int | None,
) -> tuple[DelayID, Timestamp]:
"""
Inserts a new delayed event in the DB.
@@ -148,6 +150,7 @@ def add_delayed_event_txn(txn: LoggingTransaction) -> Timestamp:
"state_key": state_key,
"origin_server_ts": origin_server_ts,
"content": json_encoder.encode(content),
+ "sticky_duration_ms": sticky_duration_ms,
},
)
@@ -299,6 +302,7 @@ def process_timeout_delayed_events_txn(
"send_ts",
"content",
"device_id",
+ "sticky_duration_ms",
)
)
sql_update = "UPDATE delayed_events SET is_processed = TRUE"
@@ -344,6 +348,7 @@ def process_timeout_delayed_events_txn(
Timestamp(row[5] if row[5] is not None else row[6]),
db_to_json(row[7]),
DeviceID(row[8]) if row[8] is not None else None,
+ int(row[9]) if row[9] is not None else None,
DelayID(row[0]),
UserLocalpart(row[1]),
)
@@ -392,6 +397,7 @@ def process_target_delayed_event_txn(
origin_server_ts,
content,
device_id,
+ sticky_duration_ms,
user_localpart
""",
(delay_id,),
@@ -407,8 +413,9 @@ def process_target_delayed_event_txn(
Timestamp(row[3]) if row[3] is not None else None,
db_to_json(row[4]),
DeviceID(row[5]) if row[5] is not None else None,
+ int(row[6]) if row[6] is not None else None,
DelayID(delay_id),
- UserLocalpart(row[6]),
+ UserLocalpart(row[7]),
)
return event, self._get_next_delayed_event_send_ts_txn(txn)
diff --git a/synapse/storage/databases/main/events.py b/synapse/storage/databases/main/events.py
index 60fc884c3a..cb452dbc9b 100644
--- a/synapse/storage/databases/main/events.py
+++ b/synapse/storage/databases/main/events.py
@@ -264,6 +264,7 @@ def __init__(
self.database_engine = db.engine
self._clock = hs.get_clock()
self._instance_name = hs.get_instance_name()
+ self._msc4354_enabled = hs.config.experimental.msc4354_enabled
self._ephemeral_messages_enabled = hs.config.server.enable_ephemeral_messages
self.is_mine_id = hs.is_mine_id
@@ -1185,6 +1186,11 @@ def _persist_events_txn(
sliding_sync_table_changes,
)
+ if self._msc4354_enabled:
+ self.store.insert_sticky_events_txn(
+ txn, [ev for ev, _ in events_and_contexts]
+ )
+
# We only update the sliding sync tables for non-backfilled events.
self._update_sliding_sync_tables_with_new_persisted_events_txn(
txn, room_id, events_and_contexts
@@ -2646,6 +2652,11 @@ def _update_outliers_txn(
# event isn't an outlier any more.
self._update_backward_extremeties(txn, [event])
+ if self._msc4354_enabled and event.sticky_duration():
+ # The de-outliered event is sticky. Update the sticky events table to ensure
+ # we deliver this down /sync.
+ self.store.insert_sticky_events_txn(txn, [event])
+
return [ec for ec in events_and_contexts if ec[0] not in to_remove]
def _store_event_txn(
diff --git a/synapse/storage/databases/main/sticky_events.py b/synapse/storage/databases/main/sticky_events.py
new file mode 100644
index 0000000000..101306296e
--- /dev/null
+++ b/synapse/storage/databases/main/sticky_events.py
@@ -0,0 +1,322 @@
+#
+# This file is licensed under the Affero General Public License (AGPL) version 3.
+#
+# Copyright (C) 2025 New Vector, Ltd
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# See the GNU Affero General Public License for more details:
+# .
+import logging
+import random
+from dataclasses import dataclass
+from typing import (
+ TYPE_CHECKING,
+)
+
+from twisted.internet.defer import Deferred
+
+from synapse.events import EventBase
+from synapse.replication.tcp.streams._base import StickyEventsStream
+from synapse.storage.database import (
+ DatabasePool,
+ LoggingDatabaseConnection,
+ LoggingTransaction,
+)
+from synapse.storage.databases.main.cache import CacheInvalidationWorkerStore
+from synapse.storage.databases.main.state import StateGroupWorkerStore
+from synapse.storage.engines import PostgresEngine, Sqlite3Engine
+from synapse.storage.util.id_generators import MultiWriterIdGenerator
+from synapse.util.duration import Duration
+
+if TYPE_CHECKING:
+ from synapse.server import HomeServer
+
+logger = logging.getLogger(__name__)
+
+DELETE_EXPIRED_STICKY_EVENTS_INTERVAL = Duration(hours=1)
+"""
+Remove entries from the sticky_events table at this frequency.
+Note: don't be misled, we still honour shorter expiration timeouts,
+because readers of the sticky_events table filter out expired sticky events
+themselves, even if they aren't deleted from the table yet.
+
+Currently just an arbitrary choice.
+Frequent enough to clean up expired sticky events promptly,
+especially given the short cap on the lifetime of sticky events.
+"""
+
+
+@dataclass(frozen=True)
+class StickyEventUpdate:
+ stream_id: int
+ room_id: str
+ event_id: str
+ soft_failed: bool
+
+
+class StickyEventsWorkerStore(StateGroupWorkerStore, CacheInvalidationWorkerStore):
+ def __init__(
+ self,
+ database: DatabasePool,
+ db_conn: LoggingDatabaseConnection,
+ hs: "HomeServer",
+ ):
+ super().__init__(database, db_conn, hs)
+
+ self._can_write_to_sticky_events = (
+ self._instance_name in hs.config.worker.writers.events
+ )
+
+ # Technically this means we will cleanup N times, once per event persister, maybe put on master?
+ if self._can_write_to_sticky_events:
+ # Start a looping call to clean up the `sticky_events` table
+ #
+ # Because this will run once per event persister (for now),
+ # randomly stagger the initial time so that they don't all
+ # coincide with each other if the workers are deployed at the
+ # same time. This allows each cleanup to be somewhat more effective
+ # than if they all started at the same time, as they would all be
+ # cleaning up the same thing whereas each worker gets to clean up a little
+ # throughout the hour when they're staggered.
+ #
+ # Concurrent execution of the same deletions could also lead to
+ # repeatable serialisation violations in the database transaction,
+ # meaning we'd have to retry the transaction several times.
+ #
+ # This staggering is not critical, it's just best-effort.
+ self.clock.call_later(
+ # random() is 0.0 to 1.0
+ DELETE_EXPIRED_STICKY_EVENTS_INTERVAL * random.random(),
+ self.clock.looping_call,
+ self._run_background_cleanup,
+ DELETE_EXPIRED_STICKY_EVENTS_INTERVAL,
+ )
+
+ self._sticky_events_id_gen: MultiWriterIdGenerator = MultiWriterIdGenerator(
+ db_conn=db_conn,
+ db=database,
+ notifier=hs.get_replication_notifier(),
+ stream_name="sticky_events",
+ server_name=self.server_name,
+ instance_name=self._instance_name,
+ tables=[
+ ("sticky_events", "instance_name", "stream_id"),
+ ],
+ sequence_name="sticky_events_sequence",
+ writers=hs.config.worker.writers.events,
+ )
+
+ if hs.config.experimental.msc4354_enabled and isinstance(
+ self.database_engine, Sqlite3Engine
+ ):
+ import sqlite3
+
+ if sqlite3.sqlite_version_info < (3, 40, 0):
+ raise RuntimeError(
+ f"Experimental MSC4354 Sticky Events enabled but SQLite3 version is too old: {sqlite3.sqlite_version_info}, must be at least 3.40. Disable MSC4354 Sticky Events, switch to Postgres, or upgrade SQLite. See https://github.com/element-hq/synapse/issues/19428"
+ )
+
+ def process_replication_position(
+ self, stream_name: str, instance_name: str, token: int
+ ) -> None:
+ if stream_name == StickyEventsStream.NAME:
+ self._sticky_events_id_gen.advance(instance_name, token)
+ super().process_replication_position(stream_name, instance_name, token)
+
+ def get_max_sticky_events_stream_id(self) -> int:
+ """Get the current maximum stream_id for thread subscriptions.
+
+ Returns:
+ The maximum stream_id
+ """
+ return self._sticky_events_id_gen.get_current_token()
+
+ def get_sticky_events_stream_id_generator(self) -> MultiWriterIdGenerator:
+ return self._sticky_events_id_gen
+
+ async def get_updated_sticky_events(
+ self, *, from_id: int, to_id: int, limit: int
+ ) -> list[StickyEventUpdate]:
+ """Get updates to sticky events between two stream IDs.
+
+ Bounds: from_id < ... <= to_id
+
+ Args:
+ from_id: The starting stream ID (exclusive)
+ to_id: The ending stream ID (inclusive)
+ limit: The maximum number of rows to return
+
+ Returns:
+ list of StickyEventUpdate update rows
+ """
+
+ if not self.hs.config.experimental.msc4354_enabled:
+ # We need to prevent `_get_updated_sticky_events_txn`
+ # from running when MSC4354 is turned off, because the query used
+ # for SQLite is not compatible with Ubuntu 22.04 (as used in our CI olddeps run).
+ # It's technically out of support.
+ # See: https://github.com/element-hq/synapse/issues/19428
+ return []
+
+ return await self.db_pool.runInteraction(
+ "get_updated_sticky_events",
+ self._get_updated_sticky_events_txn,
+ from_id,
+ to_id,
+ limit,
+ )
+
+ def _get_updated_sticky_events_txn(
+ self, txn: LoggingTransaction, from_id: int, to_id: int, limit: int
+ ) -> list[StickyEventUpdate]:
+ if isinstance(self.database_engine, PostgresEngine):
+ expr_soft_failed = "COALESCE(((ej.internal_metadata::jsonb)->>'soft_failed')::boolean, FALSE)"
+ else:
+ expr_soft_failed = "COALESCE(ej.internal_metadata->>'soft_failed', FALSE)"
+
+ txn.execute(
+ f"""
+ SELECT se.stream_id, se.room_id, se.event_id,
+ {expr_soft_failed} AS "soft_failed"
+ FROM sticky_events se
+ INNER JOIN event_json ej USING (event_id)
+ WHERE ? < stream_id AND stream_id <= ?
+ LIMIT ?
+ """,
+ (from_id, to_id, limit),
+ )
+
+ return [
+ StickyEventUpdate(
+ stream_id=stream_id,
+ room_id=room_id,
+ event_id=event_id,
+ soft_failed=bool(soft_failed),
+ )
+ for stream_id, room_id, event_id, soft_failed in txn
+ ]
+
+ def insert_sticky_events_txn(
+ self,
+ txn: LoggingTransaction,
+ events: list[EventBase],
+ ) -> None:
+ """
+ Insert events into the sticky_events table.
+
+ Skips inserting events:
+ - if they are considered spammy by the policy server;
+ (unsure if correct, track: https://github.com/matrix-org/matrix-spec-proposals/pull/4354#discussion_r2727593350)
+ - if they are rejected;
+ - if they are outliers (they should be reconsidered for insertion when de-outliered); or
+ - if they are not sticky (e.g. if the stickiness expired).
+
+ Skipping the insertion of these types of 'invalid' events is useful for performance reasons because
+ they would fill up the table yet we wouldn't show them to clients anyway.
+
+ Since syncing clients can't (easily?) 'skip over' sticky events (due to being in-order, reliably delivered),
+ tracking loads of invalid events in the table could make it expensive for servers to retrieve the sticky events that are actually valid.
+
+ For instance, someone spamming 1000s of rejected or 'policy_server_spammy' events could clog up this table in a way that means we either
+ have to deliver empty payloads to syncing clients, or consider substantially more than 100 events in order to gather a 100-sized batch to send down.
+ """
+
+ now_ms = self.clock.time_msec()
+ # event, expires_at
+ sticky_events: list[tuple[EventBase, int]] = []
+ for ev in events:
+ # MSC: Note: policy servers and other similar antispam techniques still apply to these events.
+ if ev.internal_metadata.policy_server_spammy:
+ continue
+ # We shouldn't be passed rejected events, but if we do, we filter them out too.
+ if ev.rejected_reason is not None:
+ continue
+ # We can't persist outlier sticky events as we don't know the room state at that event
+ if ev.internal_metadata.is_outlier():
+ continue
+ sticky_duration = ev.sticky_duration()
+ if sticky_duration is None:
+ continue
+ # Calculate the end time as start_time + effecitve sticky duration
+ expires_at = min(ev.origin_server_ts, now_ms) + sticky_duration.as_millis()
+ # Filter out already expired sticky events
+ if expires_at <= now_ms:
+ continue
+
+ sticky_events.append((ev, expires_at))
+
+ if len(sticky_events) == 0:
+ return
+
+ logger.info(
+ "inserting %d sticky events in room %s",
+ len(sticky_events),
+ sticky_events[0][0].room_id,
+ )
+
+ # Generate stream_ids in one go
+ sticky_events_with_ids = zip(
+ sticky_events,
+ self._sticky_events_id_gen.get_next_mult_txn(txn, len(sticky_events)),
+ strict=True,
+ )
+
+ self.db_pool.simple_insert_many_txn(
+ txn,
+ "sticky_events",
+ keys=(
+ "instance_name",
+ "stream_id",
+ "room_id",
+ "event_id",
+ "event_stream_ordering",
+ "sender",
+ "expires_at",
+ ),
+ values=[
+ (
+ self._instance_name,
+ stream_id,
+ ev.room_id,
+ ev.event_id,
+ ev.internal_metadata.stream_ordering,
+ ev.sender,
+ expires_at,
+ )
+ for (ev, expires_at), stream_id in sticky_events_with_ids
+ ],
+ )
+
+ async def _delete_expired_sticky_events(self) -> None:
+ await self.db_pool.runInteraction(
+ "_delete_expired_sticky_events",
+ self._delete_expired_sticky_events_txn,
+ self.clock.time_msec(),
+ )
+
+ def _delete_expired_sticky_events_txn(
+ self, txn: LoggingTransaction, now: int
+ ) -> None:
+ """
+ From the `sticky_events` table, deletes all entries whose expiry is in the past
+ (older than `now`).
+
+ This is fine because we don't consider the events as sticky anymore when that's
+ happened.
+ """
+ txn.execute(
+ """
+ DELETE FROM sticky_events WHERE expires_at < ?
+ """,
+ (now,),
+ )
+
+ def _run_background_cleanup(self) -> Deferred:
+ return self.hs.run_as_background_process(
+ "delete_expired_sticky_events",
+ self._delete_expired_sticky_events,
+ )
diff --git a/synapse/storage/schema/main/delta/93/01_sticky_events.sql b/synapse/storage/schema/main/delta/93/01_sticky_events.sql
new file mode 100644
index 0000000000..59fded5959
--- /dev/null
+++ b/synapse/storage/schema/main/delta/93/01_sticky_events.sql
@@ -0,0 +1,60 @@
+--
+-- This file is licensed under the Affero General Public License (AGPL) version 3.
+--
+-- Copyright (C) 2025 New Vector, Ltd
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU Affero General Public License as
+-- published by the Free Software Foundation, either version 3 of the
+-- License, or (at your option) any later version.
+--
+-- See the GNU Affero General Public License for more details:
+-- .
+
+-- Tracks sticky events.
+-- Excludes 'policy_server_spammy' events, outliers, rejected events.
+--
+-- Skipping the insertion of these types of 'invalid' events is useful for performance reasons because
+-- they would fill up the table yet we wouldn't show them to clients anyway.
+--
+-- Since syncing clients can't (easily) 'skip over' sticky events (due to being in-order, reliably delivered),
+-- tracking loads of invalid events in the table could make it expensive for servers to retrieve the sticky events that are actually valid.
+--
+-- For instance, someone spamming 1000s of rejected or 'policy_server_spammy' events could clog up this table in a way that means we either
+-- have to deliver empty payloads to syncing clients, or consider substantially more than 100 events in order to gather a 100-sized batch to send down.
+--
+-- May contain sticky events that have expired since being inserted,
+-- although they will be periodically cleaned up in the background.
+CREATE TABLE sticky_events (
+ -- Position in the sticky events stream
+ stream_id INTEGER NOT NULL PRIMARY KEY,
+
+ -- Name of the worker sending this. (This makes the stream compatible with multiple writers.)
+ instance_name TEXT NOT NULL,
+
+ -- The event ID of the sticky event itself.
+ event_id TEXT NOT NULL,
+
+ -- The room ID that the sticky event is in.
+ -- Denormalised for performance. (Safe as it's an immutable property of the event.)
+ room_id TEXT NOT NULL,
+
+ -- The stream_ordering of the event.
+ -- Denormalised for performance since we will want to sort these by stream_ordering
+ -- when fetching them. (Safe as it's an immutable property of the event.)
+ event_stream_ordering INTEGER NOT NULL UNIQUE,
+
+ -- Sender of the sticky event.
+ -- Denormalised for performance so we can query only for sticky events originating
+ -- from our homeserver. (Safe as it's an immutable property of the event.)
+ sender TEXT NOT NULL,
+
+ -- When the sticky event expires, in milliseconds since the Unix epoch.
+ expires_at BIGINT NOT NULL
+);
+
+-- For pulling out sticky events by room at send time, obeying stream ordering range limits.
+CREATE INDEX sticky_events_room_idx ON sticky_events (room_id, event_stream_ordering);
+
+-- A optional integer for combining sticky events with delayed events. Used at send time.
+ALTER TABLE delayed_events ADD COLUMN sticky_duration_ms BIGINT;
diff --git a/synapse/storage/schema/main/delta/93/01_sticky_events_seq.sql.postgres b/synapse/storage/schema/main/delta/93/01_sticky_events_seq.sql.postgres
new file mode 100644
index 0000000000..9ba72856bc
--- /dev/null
+++ b/synapse/storage/schema/main/delta/93/01_sticky_events_seq.sql.postgres
@@ -0,0 +1,18 @@
+--
+-- This file is licensed under the Affero General Public License (AGPL) version 3.
+--
+-- Copyright (C) 2025 New Vector, Ltd
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU Affero General Public License as
+-- published by the Free Software Foundation, either version 3 of the
+-- License, or (at your option) any later version.
+--
+-- See the GNU Affero General Public License for more details:
+-- .
+
+CREATE SEQUENCE sticky_events_sequence;
+-- Synapse streams start at 2, because the default position is 1
+-- so any item inserted at position 1 is ignored.
+-- We have to use nextval not START WITH 2, see https://github.com/element-hq/synapse/issues/18712
+SELECT nextval('sticky_events_sequence');
diff --git a/synapse/streams/events.py b/synapse/streams/events.py
index 143f659499..d2720fb959 100644
--- a/synapse/streams/events.py
+++ b/synapse/streams/events.py
@@ -84,6 +84,7 @@ def get_current_token(self) -> StreamToken:
self._instance_name
)
thread_subscriptions_key = self.store.get_max_thread_subscriptions_stream_id()
+ sticky_events_key = self.store.get_max_sticky_events_stream_id()
token = StreamToken(
room_key=self.sources.room.get_current_key(),
@@ -98,6 +99,7 @@ def get_current_token(self) -> StreamToken:
groups_key=0,
un_partial_stated_rooms_key=un_partial_stated_rooms_key,
thread_subscriptions_key=thread_subscriptions_key,
+ sticky_events_key=sticky_events_key,
)
return token
@@ -125,6 +127,7 @@ async def bound_future_token(self, token: StreamToken) -> StreamToken:
StreamKeyType.DEVICE_LIST: self.store.get_device_stream_id_generator(),
StreamKeyType.UN_PARTIAL_STATED_ROOMS: self.store.get_un_partial_stated_rooms_id_generator(),
StreamKeyType.THREAD_SUBSCRIPTIONS: self.store.get_thread_subscriptions_stream_id_generator(),
+ StreamKeyType.STICKY_EVENTS: self.store.get_sticky_events_stream_id_generator(),
}
for _, key in StreamKeyType.__members__.items():
diff --git a/synapse/types/__init__.py b/synapse/types/__init__.py
index 99eefb8acb..fb1f1192b7 100644
--- a/synapse/types/__init__.py
+++ b/synapse/types/__init__.py
@@ -1006,6 +1006,7 @@ class StreamKeyType(Enum):
DEVICE_LIST = "device_list_key"
UN_PARTIAL_STATED_ROOMS = "un_partial_stated_rooms_key"
THREAD_SUBSCRIPTIONS = "thread_subscriptions_key"
+ STICKY_EVENTS = "sticky_events_key"
@attr.s(slots=True, frozen=True, auto_attribs=True)
@@ -1027,6 +1028,7 @@ class StreamToken:
9. `groups_key`: `1` (note that this key is now unused)
10. `un_partial_stated_rooms_key`: `379`
11. `thread_subscriptions_key`: 4242
+ 12. `sticky_events_key`: 4141
You can see how many of these keys correspond to the various
fields in a "/sync" response:
@@ -1086,6 +1088,7 @@ class StreamToken:
groups_key: int
un_partial_stated_rooms_key: int
thread_subscriptions_key: int
+ sticky_events_key: int
_SEPARATOR = "_"
START: ClassVar["StreamToken"]
@@ -1114,6 +1117,7 @@ async def from_string(cls, store: "DataStore", string: str) -> "StreamToken":
groups_key,
un_partial_stated_rooms_key,
thread_subscriptions_key,
+ sticky_events_key,
) = keys
return cls(
@@ -1130,6 +1134,7 @@ async def from_string(cls, store: "DataStore", string: str) -> "StreamToken":
groups_key=int(groups_key),
un_partial_stated_rooms_key=int(un_partial_stated_rooms_key),
thread_subscriptions_key=int(thread_subscriptions_key),
+ sticky_events_key=int(sticky_events_key),
)
except CancelledError:
raise
@@ -1153,6 +1158,7 @@ async def to_string(self, store: "DataStore") -> str:
str(self.groups_key),
str(self.un_partial_stated_rooms_key),
str(self.thread_subscriptions_key),
+ str(self.sticky_events_key),
]
)
@@ -1218,6 +1224,7 @@ def get_field(
StreamKeyType.TYPING,
StreamKeyType.UN_PARTIAL_STATED_ROOMS,
StreamKeyType.THREAD_SUBSCRIPTIONS,
+ StreamKeyType.STICKY_EVENTS,
],
) -> int: ...
@@ -1274,7 +1281,7 @@ def __str__(self) -> str:
f"account_data: {self.account_data_key}, push_rules: {self.push_rules_key}, "
f"to_device: {self.to_device_key}, device_list: {self.device_list_key}, "
f"groups: {self.groups_key}, un_partial_stated_rooms: {self.un_partial_stated_rooms_key},"
- f"thread_subscriptions: {self.thread_subscriptions_key})"
+ f"thread_subscriptions: {self.thread_subscriptions_key}, sticky_events: {self.sticky_events_key})"
)
@@ -1290,6 +1297,7 @@ def __str__(self) -> str:
groups_key=0,
un_partial_stated_rooms_key=0,
thread_subscriptions_key=0,
+ sticky_events_key=0,
)
diff --git a/synapse/visibility.py b/synapse/visibility.py
index 452a2d50fb..5ba2a14a24 100644
--- a/synapse/visibility.py
+++ b/synapse/visibility.py
@@ -237,6 +237,20 @@ def allowed(event: EventBase) -> EventBase | None:
# to the cache!
cloned = clone_event(filtered)
cloned.unsigned[EventUnsignedContentFields.MEMBERSHIP] = user_membership
+ if storage.main.config.experimental.msc4354_enabled:
+ sticky_duration = cloned.sticky_duration()
+ if sticky_duration:
+ now_ms = storage.main.clock.time_msec()
+ expires_at = (
+ # min() ensures that the origin server can't lie about the time and
+ # send the event 'in the future', as that would allow them to exceed
+ # the 1 hour limit on stickiness duration.
+ min(cloned.origin_server_ts, now_ms) + sticky_duration.as_millis()
+ )
+ if expires_at > now_ms:
+ cloned.unsigned[EventUnsignedContentFields.STICKY_TTL] = (
+ expires_at - now_ms
+ )
return cloned
diff --git a/tests/rest/admin/test_room.py b/tests/rest/admin/test_room.py
index 4070bcaeaa..b32665eb73 100644
--- a/tests/rest/admin/test_room.py
+++ b/tests/rest/admin/test_room.py
@@ -2545,7 +2545,7 @@ def test_timestamp_to_event(self) -> None:
def test_topo_token_is_accepted(self) -> None:
"""Test Topo Token is accepted."""
- token = "t1-0_0_0_0_0_0_0_0_0_0_0"
+ token = "t1-0_0_0_0_0_0_0_0_0_0_0_0"
channel = self.make_request(
"GET",
"/_synapse/admin/v1/rooms/%s/messages?from=%s" % (self.room_id, token),
@@ -2559,7 +2559,7 @@ def test_topo_token_is_accepted(self) -> None:
def test_stream_token_is_accepted_for_fwd_pagianation(self) -> None:
"""Test that stream token is accepted for forward pagination."""
- token = "s0_0_0_0_0_0_0_0_0_0_0"
+ token = "s0_0_0_0_0_0_0_0_0_0_0_0"
channel = self.make_request(
"GET",
"/_synapse/admin/v1/rooms/%s/messages?from=%s" % (self.room_id, token),
diff --git a/tests/rest/client/test_rooms.py b/tests/rest/client/test_rooms.py
index 926560afd6..f85c9939ce 100644
--- a/tests/rest/client/test_rooms.py
+++ b/tests/rest/client/test_rooms.py
@@ -2245,7 +2245,7 @@ def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None:
self.room_id = self.helper.create_room_as(self.user_id)
def test_topo_token_is_accepted(self) -> None:
- token = "t1-0_0_0_0_0_0_0_0_0_0_0"
+ token = "t1-0_0_0_0_0_0_0_0_0_0_0_0"
channel = self.make_request(
"GET", "/rooms/%s/messages?access_token=x&from=%s" % (self.room_id, token)
)
@@ -2256,7 +2256,7 @@ def test_topo_token_is_accepted(self) -> None:
self.assertTrue("end" in channel.json_body)
def test_stream_token_is_accepted_for_fwd_pagianation(self) -> None:
- token = "s0_0_0_0_0_0_0_0_0_0_0"
+ token = "s0_0_0_0_0_0_0_0_0_0_0_0"
channel = self.make_request(
"GET", "/rooms/%s/messages?access_token=x&from=%s" % (self.room_id, token)
)
diff --git a/tests/rest/client/test_sticky_events.py b/tests/rest/client/test_sticky_events.py
new file mode 100644
index 0000000000..a6e704fe8c
--- /dev/null
+++ b/tests/rest/client/test_sticky_events.py
@@ -0,0 +1,179 @@
+#
+# This file is licensed under the Affero General Public License (AGPL) version 3.
+#
+# Copyright (C) 2025 New Vector, Ltd
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# See the GNU Affero General Public License for more details:
+# .
+#
+#
+
+import sqlite3
+
+from twisted.internet.testing import MemoryReactor
+
+from synapse.api.constants import EventTypes, EventUnsignedContentFields
+from synapse.rest import admin
+from synapse.rest.client import login, register, room
+from synapse.server import HomeServer
+from synapse.types import JsonDict
+from synapse.util.clock import Clock
+from synapse.util.duration import Duration
+
+from tests import unittest
+from tests.utils import USE_POSTGRES_FOR_TESTS
+
+
+class StickyEventsClientTestCase(unittest.HomeserverTestCase):
+ """
+ Tests for the client-server API parts of MSC4354: Sticky Events
+ """
+
+ if not USE_POSTGRES_FOR_TESTS and sqlite3.sqlite_version_info < (3, 40, 0):
+ # We need the JSON functionality in SQLite
+ skip = f"SQLite version is too old to support sticky events: {sqlite3.sqlite_version_info} (See https://github.com/element-hq/synapse/issues/19428)"
+
+ servlets = [
+ room.register_servlets,
+ login.register_servlets,
+ register.register_servlets,
+ admin.register_servlets,
+ ]
+
+ def default_config(self) -> JsonDict:
+ config = super().default_config()
+ config["experimental_features"] = {"msc4354_enabled": True}
+ return config
+
+ def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None:
+ # Register an account
+ self.user_id = self.register_user("user1", "pass")
+ self.token = self.login(self.user_id, "pass")
+
+ # Create a room
+ self.room_id = self.helper.create_room_as(self.user_id, tok=self.token)
+
+ def _assert_event_sticky_for(self, event_id: str, sticky_ttl: int) -> None:
+ channel = self.make_request(
+ "GET",
+ f"/rooms/{self.room_id}/event/{event_id}",
+ access_token=self.token,
+ )
+
+ self.assertEqual(
+ channel.code, 200, f"could not retrieve event {event_id}: {channel.result}"
+ )
+ event = channel.json_body
+
+ self.assertIn(
+ EventUnsignedContentFields.STICKY_TTL,
+ event["unsigned"],
+ f"No {EventUnsignedContentFields.STICKY_TTL} field in {event_id}; event not sticky: {event}",
+ )
+ self.assertEqual(
+ event["unsigned"][EventUnsignedContentFields.STICKY_TTL],
+ sticky_ttl,
+ f"{event_id} had an unexpected sticky TTL: {event}",
+ )
+
+ def _assert_event_not_sticky(self, event_id: str) -> None:
+ channel = self.make_request(
+ "GET",
+ f"/rooms/{self.room_id}/event/{event_id}",
+ access_token=self.token,
+ )
+
+ self.assertEqual(
+ channel.code, 200, f"could not retrieve event {event_id}: {channel.result}"
+ )
+ event = channel.json_body
+
+ self.assertNotIn(
+ EventUnsignedContentFields.STICKY_TTL,
+ event["unsigned"],
+ f"{EventUnsignedContentFields.STICKY_TTL} field unexpectedly found in {event_id}: {event}",
+ )
+
+ def test_sticky_event_via_event_endpoint(self) -> None:
+ # Arrange: Send a sticky event with a specific duration
+ sticky_event_response = self.helper.send_sticky_event(
+ self.room_id,
+ EventTypes.Message,
+ duration=Duration(minutes=1),
+ content={"body": "sticky message", "msgtype": "m.text"},
+ tok=self.token,
+ )
+ event_id = sticky_event_response["event_id"]
+
+ # If we request the event immediately, it will still have
+ # 1 minute of stickiness
+ # The other 100 ms is advanced in FakeChannel.await_result.
+ self._assert_event_sticky_for(event_id, 59_900)
+
+ # But if we advance time by 59.799 seconds...
+ # we will get the event on its last millisecond of stickiness
+ # The other 100 ms is advanced in FakeChannel.await_result.
+ self.reactor.advance(59.799)
+ self._assert_event_sticky_for(event_id, 1)
+
+ # Advancing time any more, the event is no longer sticky
+ self.reactor.advance(0.001)
+ self._assert_event_not_sticky(event_id)
+
+
+class StickyEventsDisabledClientTestCase(unittest.HomeserverTestCase):
+ """
+ Tests client-facing behaviour of MSC4354: Sticky Events when the feature is
+ disabled.
+ """
+
+ servlets = [
+ room.register_servlets,
+ login.register_servlets,
+ register.register_servlets,
+ admin.register_servlets,
+ ]
+
+ def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None:
+ # Register an account
+ self.user_id = self.register_user("user1", "pass")
+ self.token = self.login(self.user_id, "pass")
+
+ # Create a room
+ self.room_id = self.helper.create_room_as(self.user_id, tok=self.token)
+
+ def _assert_event_not_sticky(self, event_id: str) -> None:
+ channel = self.make_request(
+ "GET",
+ f"/rooms/{self.room_id}/event/{event_id}",
+ access_token=self.token,
+ )
+
+ self.assertEqual(
+ channel.code, 200, f"could not retrieve event {event_id}: {channel.result}"
+ )
+ event = channel.json_body
+
+ self.assertNotIn(
+ EventUnsignedContentFields.STICKY_TTL,
+ event["unsigned"],
+ f"{EventUnsignedContentFields.STICKY_TTL} field unexpectedly found in {event_id}: {event}",
+ )
+
+ def test_sticky_event_via_event_endpoint(self) -> None:
+ sticky_event_response = self.helper.send_sticky_event(
+ self.room_id,
+ EventTypes.Message,
+ duration=Duration(minutes=1),
+ content={"body": "sticky message", "msgtype": "m.text"},
+ tok=self.token,
+ )
+ event_id = sticky_event_response["event_id"]
+
+ # Since the feature is disabled, the event isn't sticky
+ self._assert_event_not_sticky(event_id)
diff --git a/tests/rest/client/utils.py b/tests/rest/client/utils.py
index b3808d75bb..bfa8e6f3d8 100644
--- a/tests/rest/client/utils.py
+++ b/tests/rest/client/utils.py
@@ -48,6 +48,7 @@
from synapse.api.errors import Codes
from synapse.server import HomeServer
from synapse.types import JsonDict
+from synapse.util.duration import Duration
from tests.server import FakeChannel, make_request
from tests.test_utils.html_parsers import TestHtmlParser
@@ -453,6 +454,44 @@ def send_event(
return channel.json_body
+ def send_sticky_event(
+ self,
+ room_id: str,
+ type: str,
+ *,
+ duration: Duration,
+ content: dict | None = None,
+ txn_id: str | None = None,
+ tok: str | None = None,
+ expect_code: int = HTTPStatus.OK,
+ custom_headers: Iterable[tuple[AnyStr, AnyStr]] | None = None,
+ ) -> JsonDict:
+ """
+ Send an event that has a sticky duration according to MSC4354.
+ """
+
+ if txn_id is None:
+ txn_id = f"m{time.time()}"
+
+ path = f"/_matrix/client/r0/rooms/{room_id}/send/{type}/{txn_id}?org.matrix.msc4354.sticky_duration_ms={duration.as_millis()}"
+ if tok:
+ path = path + f"&access_token={tok}"
+
+ channel = make_request(
+ self.reactor,
+ self.site,
+ "PUT",
+ path,
+ content or {},
+ custom_headers=custom_headers,
+ )
+
+ assert channel.code == expect_code, (
+ f"Expected: {expect_code}, got: {channel.code}, resp: {channel.result['body']!r}"
+ )
+
+ return channel.json_body
+
def get_event(
self,
room_id: str,
diff --git a/tests/storage/test_sticky_events.py b/tests/storage/test_sticky_events.py
new file mode 100644
index 0000000000..60243cb2f4
--- /dev/null
+++ b/tests/storage/test_sticky_events.py
@@ -0,0 +1,278 @@
+#
+# This file is licensed under the Affero General Public License (AGPL) version 3.
+#
+# Copyright (C) 2026 Element Creations Ltd.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# See the GNU Affero General Public License for more details:
+# .
+import sqlite3
+
+from twisted.internet.testing import MemoryReactor
+
+from synapse.api.constants import (
+ EventContentFields,
+ EventTypes,
+ Membership,
+ StickyEvent,
+ StickyEventField,
+)
+from synapse.api.room_versions import RoomVersions
+from synapse.rest import admin
+from synapse.rest.client import login, register, room
+from synapse.server import HomeServer
+from synapse.types import JsonDict, create_requester
+from synapse.util.clock import Clock
+from synapse.util.duration import Duration
+
+from tests import unittest
+from tests.utils import USE_POSTGRES_FOR_TESTS
+
+
+class StickyEventsTestCase(unittest.HomeserverTestCase):
+ """
+ Tests for the storage functions related to MSC4354: Sticky Events
+ """
+
+ if not USE_POSTGRES_FOR_TESTS and sqlite3.sqlite_version_info < (3, 40, 0):
+ # We need the JSON functionality in SQLite
+ skip = f"SQLite version is too old to support sticky events: {sqlite3.sqlite_version_info} (See https://github.com/element-hq/synapse/issues/19428)"
+
+ servlets = [
+ room.register_servlets,
+ login.register_servlets,
+ register.register_servlets,
+ admin.register_servlets,
+ ]
+
+ def default_config(self) -> JsonDict:
+ config = super().default_config()
+ config["experimental_features"] = {"msc4354_enabled": True}
+ return config
+
+ def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None:
+ self.store = self.hs.get_datastores().main
+
+ # Register an account and create a room
+ self.user_id = self.register_user("user", "pass")
+ self.token = self.login(self.user_id, "pass")
+ self.room_id = self.helper.create_room_as(self.user_id, tok=self.token)
+
+ def test_get_updated_sticky_events(self) -> None:
+ """Test getting updated sticky events between stream IDs."""
+ # Get the starting stream_id
+ start_id = self.store.get_max_sticky_events_stream_id()
+
+ event_id_1 = self.helper.send_sticky_event(
+ self.room_id,
+ EventTypes.Message,
+ duration=Duration(minutes=1),
+ content={"body": "message 1", "msgtype": "m.text"},
+ tok=self.token,
+ )["event_id"]
+
+ mid_id = self.store.get_max_sticky_events_stream_id()
+
+ event_id_2 = self.helper.send_sticky_event(
+ self.room_id,
+ EventTypes.Message,
+ duration=Duration(minutes=1),
+ content={"body": "message 2", "msgtype": "m.text"},
+ tok=self.token,
+ )["event_id"]
+
+ end_id = self.store.get_max_sticky_events_stream_id()
+
+ # Get all updates
+ updates = self.get_success(
+ self.store.get_updated_sticky_events(
+ from_id=start_id, to_id=end_id, limit=10
+ )
+ )
+ self.assertEqual(len(updates), 2)
+ self.assertEqual(updates[0].event_id, event_id_1)
+ self.assertEqual(updates[0].soft_failed, False)
+ self.assertEqual(updates[1].event_id, event_id_2)
+ self.assertEqual(updates[1].soft_failed, False)
+
+ # Get only the second update
+ updates = self.get_success(
+ self.store.get_updated_sticky_events(from_id=mid_id, to_id=end_id, limit=10)
+ )
+ self.assertEqual(len(updates), 1)
+ self.assertEqual(updates[0].event_id, event_id_2)
+ self.assertEqual(updates[0].soft_failed, False)
+
+ def test_delete_expired_sticky_events(self) -> None:
+ """Test deletion of expired sticky events."""
+ # Insert an expired event by advancing time past its duration
+ self.helper.send_sticky_event(
+ self.room_id,
+ EventTypes.Message,
+ duration=Duration(milliseconds=1),
+ content={"body": "expired message", "msgtype": "m.text"},
+ tok=self.token,
+ )
+ self.reactor.advance(0.002)
+
+ # Insert a non-expired event
+ event_id_2 = self.helper.send_sticky_event(
+ self.room_id,
+ EventTypes.Message,
+ duration=Duration(minutes=1),
+ content={"body": "non-expired message", "msgtype": "m.text"},
+ tok=self.token,
+ )["event_id"]
+
+ end_id = self.store.get_max_sticky_events_stream_id()
+
+ # Delete expired events
+ self.get_success(self.store._delete_expired_sticky_events())
+
+ # Check that only the non-expired event remains
+ sticky_events = self.get_success(
+ self.store.db_pool.simple_select_list(
+ table="sticky_events", keyvalues=None, retcols=("stream_id", "event_id")
+ )
+ )
+ self.assertEqual(
+ sticky_events,
+ [
+ (end_id, event_id_2),
+ ],
+ )
+
+ def test_get_updated_sticky_events_with_limit(self) -> None:
+ """Test that the limit parameter works correctly."""
+ # Get the starting stream_id
+ start_id = self.store.get_max_sticky_events_stream_id()
+
+ event_id_1 = self.helper.send_sticky_event(
+ self.room_id,
+ EventTypes.Message,
+ duration=Duration(minutes=1),
+ content={"body": "message 1", "msgtype": "m.text"},
+ tok=self.token,
+ )["event_id"]
+
+ self.helper.send_sticky_event(
+ self.room_id,
+ EventTypes.Message,
+ duration=Duration(minutes=1),
+ content={"body": "message 2", "msgtype": "m.text"},
+ tok=self.token,
+ )
+
+ # Get only the first update
+ updates = self.get_success(
+ self.store.get_updated_sticky_events(
+ from_id=start_id, to_id=start_id + 2, limit=1
+ )
+ )
+ self.assertEqual(len(updates), 1)
+ self.assertEqual(updates[0].event_id, event_id_1)
+
+ def test_outlier_events_not_in_table(self) -> None:
+ """
+ Tests the behaviour of outliered and then de-outliered events in the
+ sticky_events table: they should only be added once they are de-outliered.
+ """
+ persist_controller = self.hs.get_storage_controllers().persistence
+ assert persist_controller is not None
+
+ user1_id = self.register_user("user1", "pass")
+ user2_id = self.register_user("user2", "pass")
+ user2_tok = self.login(user2_id, "pass")
+
+ start_id = self.store.get_max_sticky_events_stream_id()
+
+ room_id = self.helper.create_room_as(
+ user2_id, tok=user2_tok, room_version=RoomVersions.V10.identifier
+ )
+
+ # Create a membership event
+ event_dict = {
+ "type": EventTypes.Member,
+ "state_key": user1_id,
+ "sender": user1_id,
+ "room_id": room_id,
+ "content": {EventContentFields.MEMBERSHIP: Membership.JOIN},
+ StickyEvent.EVENT_FIELD_NAME: StickyEventField(
+ duration_ms=Duration(hours=1).as_millis()
+ ),
+ }
+
+ # Create the event twice: once as an outlier, once as a non-outlier.
+ # It's not at all obvious, but event creation before is deterministic
+ # (provided we don't change the forward extremities of the room!),
+ # so these two events are actually the same event with the same event ID.
+ (
+ event_outlier,
+ unpersisted_context_outlier,
+ ) = self.get_success(
+ self.hs.get_event_creation_handler().create_event(
+ requester=create_requester(user1_id),
+ event_dict=event_dict,
+ outlier=True,
+ )
+ )
+ (
+ event_non_outlier,
+ unpersisted_context_non_outlier,
+ ) = self.get_success(
+ self.hs.get_event_creation_handler().create_event(
+ requester=create_requester(user1_id),
+ event_dict=event_dict,
+ outlier=False,
+ )
+ )
+
+ # Safety check that we're testing what we think we are
+ self.assertEqual(event_outlier.event_id, event_non_outlier.event_id)
+
+ # Now persist the event as an outlier first of all
+ # FIXME: Should we use an `EventContext.for_outlier(...)` here?
+ # Doesn't seem to matter for this test.
+ context_outlier = self.get_success(
+ unpersisted_context_outlier.persist(event_outlier)
+ )
+ self.get_success(
+ persist_controller.persist_event(
+ event_outlier,
+ context_outlier,
+ )
+ )
+
+ # Since the event is outliered, it won't show up in the sticky_events table...
+ sticky_events = self.get_success(
+ self.store.db_pool.simple_select_list(
+ table="sticky_events", keyvalues=None, retcols=("stream_id", "event_id")
+ )
+ )
+ self.assertEqual(len(sticky_events), 0)
+
+ # Now persist the event properly so that it gets de-outliered.
+ context_non_outlier = self.get_success(
+ unpersisted_context_non_outlier.persist(event_non_outlier)
+ )
+ self.get_success(
+ persist_controller.persist_event(
+ event_non_outlier,
+ context_non_outlier,
+ )
+ )
+
+ end_id = self.store.get_max_sticky_events_stream_id()
+
+ # Check the event made it into the sticky_events table
+ updates = self.get_success(
+ self.store.get_updated_sticky_events(
+ from_id=start_id, to_id=end_id, limit=10
+ )
+ )
+ self.assertEqual(len(updates), 1)
+ self.assertEqual(updates[0].event_id, event_non_outlier.event_id)
From a52ffd67e09bd2784ca7e2a2227a90c44c7e417c Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 17 Feb 2026 13:53:39 +0100
Subject: [PATCH 06/19] Bump cryptography from 46.0.3 to 46.0.5 (#19450)
Bumps [cryptography](https://github.com/pyca/cryptography) from 46.0.3
to 46.0.5.
Changelog
Sourced from cryptography's
changelog.
46.0.5 - 2026-02-10
* An attacker could create a malicious public key that reveals portions
of your
private key when using certain uncommon elliptic curves (binary curves).
This version now includes additional security checks to prevent this
attack.
This issue only affects binary elliptic curves, which are rarely used in
real-world applications. Credit to **XlabAI Team of Tencent Xuanwu Lab
and
Atuin Automated Vulnerability Discovery Engine** for reporting the
issue.
**CVE-2026-26007**
* Support for ``SECT*`` binary elliptic curves is deprecated and will be
removed in the next release.
.. v46-0-4:
46.0.4 - 2026-01-27
Dropped support for win_arm64 wheels_.
- Updated Windows, macOS, and Linux wheels to be compiled with OpenSSL
3.5.5.
.. _v46-0-3:
Commits
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/element-hq/synapse/network/alerts).
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
poetry.lock | 107 +++++++++++++++++++++++++---------------------------
1 file changed, 51 insertions(+), 56 deletions(-)
diff --git a/poetry.lock b/poetry.lock
index 2d75fb50c8..5f1256676e 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -398,66 +398,61 @@ files = [
[[package]]
name = "cryptography"
-version = "46.0.3"
+version = "46.0.5"
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
optional = false
python-versions = "!=3.9.0,!=3.9.1,>=3.8"
groups = ["main", "dev"]
files = [
- {file = "cryptography-46.0.3-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:109d4ddfadf17e8e7779c39f9b18111a09efb969a301a31e987416a0191ed93a"},
- {file = "cryptography-46.0.3-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:09859af8466b69bc3c27bdf4f5d84a665e0f7ab5088412e9e2ec49758eca5cbc"},
- {file = "cryptography-46.0.3-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:01ca9ff2885f3acc98c29f1860552e37f6d7c7d013d7334ff2a9de43a449315d"},
- {file = "cryptography-46.0.3-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:6eae65d4c3d33da080cff9c4ab1f711b15c1d9760809dad6ea763f3812d254cb"},
- {file = "cryptography-46.0.3-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5bf0ed4490068a2e72ac03d786693adeb909981cc596425d09032d372bcc849"},
- {file = "cryptography-46.0.3-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:5ecfccd2329e37e9b7112a888e76d9feca2347f12f37918facbb893d7bb88ee8"},
- {file = "cryptography-46.0.3-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a2c0cd47381a3229c403062f764160d57d4d175e022c1df84e168c6251a22eec"},
- {file = "cryptography-46.0.3-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:549e234ff32571b1f4076ac269fcce7a808d3bf98b76c8dd560e42dbc66d7d91"},
- {file = "cryptography-46.0.3-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:c0a7bb1a68a5d3471880e264621346c48665b3bf1c3759d682fc0864c540bd9e"},
- {file = "cryptography-46.0.3-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:10b01676fc208c3e6feeb25a8b83d81767e8059e1fe86e1dc62d10a3018fa926"},
- {file = "cryptography-46.0.3-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0abf1ffd6e57c67e92af68330d05760b7b7efb243aab8377e583284dbab72c71"},
- {file = "cryptography-46.0.3-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a04bee9ab6a4da801eb9b51f1b708a1b5b5c9eb48c03f74198464c66f0d344ac"},
- {file = "cryptography-46.0.3-cp311-abi3-win32.whl", hash = "sha256:f260d0d41e9b4da1ed1e0f1ce571f97fe370b152ab18778e9e8f67d6af432018"},
- {file = "cryptography-46.0.3-cp311-abi3-win_amd64.whl", hash = "sha256:a9a3008438615669153eb86b26b61e09993921ebdd75385ddd748702c5adfddb"},
- {file = "cryptography-46.0.3-cp311-abi3-win_arm64.whl", hash = "sha256:5d7f93296ee28f68447397bf5198428c9aeeab45705a55d53a6343455dcb2c3c"},
- {file = "cryptography-46.0.3-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:00a5e7e87938e5ff9ff5447ab086a5706a957137e6e433841e9d24f38a065217"},
- {file = "cryptography-46.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c8daeb2d2174beb4575b77482320303f3d39b8e81153da4f0fb08eb5fe86a6c5"},
- {file = "cryptography-46.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:39b6755623145ad5eff1dab323f4eae2a32a77a7abef2c5089a04a3d04366715"},
- {file = "cryptography-46.0.3-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:db391fa7c66df6762ee3f00c95a89e6d428f4d60e7abc8328f4fe155b5ac6e54"},
- {file = "cryptography-46.0.3-cp314-cp314t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:78a97cf6a8839a48c49271cdcbd5cf37ca2c1d6b7fdd86cc864f302b5e9bf459"},
- {file = "cryptography-46.0.3-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:dfb781ff7eaa91a6f7fd41776ec37c5853c795d3b358d4896fdbb5df168af422"},
- {file = "cryptography-46.0.3-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:6f61efb26e76c45c4a227835ddeae96d83624fb0d29eb5df5b96e14ed1a0afb7"},
- {file = "cryptography-46.0.3-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:23b1a8f26e43f47ceb6d6a43115f33a5a37d57df4ea0ca295b780ae8546e8044"},
- {file = "cryptography-46.0.3-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:b419ae593c86b87014b9be7396b385491ad7f320bde96826d0dd174459e54665"},
- {file = "cryptography-46.0.3-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:50fc3343ac490c6b08c0cf0d704e881d0d660be923fd3076db3e932007e726e3"},
- {file = "cryptography-46.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:22d7e97932f511d6b0b04f2bfd818d73dcd5928db509460aaf48384778eb6d20"},
- {file = "cryptography-46.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:d55f3dffadd674514ad19451161118fd010988540cee43d8bc20675e775925de"},
- {file = "cryptography-46.0.3-cp314-cp314t-win32.whl", hash = "sha256:8a6e050cb6164d3f830453754094c086ff2d0b2f3a897a1d9820f6139a1f0914"},
- {file = "cryptography-46.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:760f83faa07f8b64e9c33fc963d790a2edb24efb479e3520c14a45741cd9b2db"},
- {file = "cryptography-46.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:516ea134e703e9fe26bcd1277a4b59ad30586ea90c365a87781d7887a646fe21"},
- {file = "cryptography-46.0.3-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:cb3d760a6117f621261d662bccc8ef5bc32ca673e037c83fbe565324f5c46936"},
- {file = "cryptography-46.0.3-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4b7387121ac7d15e550f5cb4a43aef2559ed759c35df7336c402bb8275ac9683"},
- {file = "cryptography-46.0.3-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:15ab9b093e8f09daab0f2159bb7e47532596075139dd74365da52ecc9cb46c5d"},
- {file = "cryptography-46.0.3-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:46acf53b40ea38f9c6c229599a4a13f0d46a6c3fa9ef19fc1a124d62e338dfa0"},
- {file = "cryptography-46.0.3-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:10ca84c4668d066a9878890047f03546f3ae0a6b8b39b697457b7757aaf18dbc"},
- {file = "cryptography-46.0.3-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:36e627112085bb3b81b19fed209c05ce2a52ee8b15d161b7c643a7d5a88491f3"},
- {file = "cryptography-46.0.3-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1000713389b75c449a6e979ffc7dcc8ac90b437048766cef052d4d30b8220971"},
- {file = "cryptography-46.0.3-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:b02cf04496f6576afffef5ddd04a0cb7d49cf6be16a9059d793a30b035f6b6ac"},
- {file = "cryptography-46.0.3-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:71e842ec9bc7abf543b47cf86b9a743baa95f4677d22baa4c7d5c69e49e9bc04"},
- {file = "cryptography-46.0.3-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:402b58fc32614f00980b66d6e56a5b4118e6cb362ae8f3fda141ba4689bd4506"},
- {file = "cryptography-46.0.3-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ef639cb3372f69ec44915fafcd6698b6cc78fbe0c2ea41be867f6ed612811963"},
- {file = "cryptography-46.0.3-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3b51b8ca4f1c6453d8829e1eb7299499ca7f313900dd4d89a24b8b87c0a780d4"},
- {file = "cryptography-46.0.3-cp38-abi3-win32.whl", hash = "sha256:6276eb85ef938dc035d59b87c8a7dc559a232f954962520137529d77b18ff1df"},
- {file = "cryptography-46.0.3-cp38-abi3-win_amd64.whl", hash = "sha256:416260257577718c05135c55958b674000baef9a1c7d9e8f306ec60d71db850f"},
- {file = "cryptography-46.0.3-cp38-abi3-win_arm64.whl", hash = "sha256:d89c3468de4cdc4f08a57e214384d0471911a3830fcdaf7a8cc587e42a866372"},
- {file = "cryptography-46.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a23582810fedb8c0bc47524558fb6c56aac3fc252cb306072fd2815da2a47c32"},
- {file = "cryptography-46.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e7aec276d68421f9574040c26e2a7c3771060bc0cff408bae1dcb19d3ab1e63c"},
- {file = "cryptography-46.0.3-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7ce938a99998ed3c8aa7e7272dca1a610401ede816d36d0693907d863b10d9ea"},
- {file = "cryptography-46.0.3-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:191bb60a7be5e6f54e30ba16fdfae78ad3a342a0599eb4193ba88e3f3d6e185b"},
- {file = "cryptography-46.0.3-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c70cc23f12726be8f8bc72e41d5065d77e4515efae3690326764ea1b07845cfb"},
- {file = "cryptography-46.0.3-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:9394673a9f4de09e28b5356e7fff97d778f8abad85c9d5ac4a4b7e25a0de7717"},
- {file = "cryptography-46.0.3-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:94cd0549accc38d1494e1f8de71eca837d0509d0d44bf11d158524b0e12cebf9"},
- {file = "cryptography-46.0.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:6b5063083824e5509fdba180721d55909ffacccc8adbec85268b48439423d78c"},
- {file = "cryptography-46.0.3.tar.gz", hash = "sha256:a8b17438104fed022ce745b362294d9ce35b4c2e45c1d958ad4a4b019285f4a1"},
+ {file = "cryptography-46.0.5-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:351695ada9ea9618b3500b490ad54c739860883df6c1f555e088eaf25b1bbaad"},
+ {file = "cryptography-46.0.5-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c18ff11e86df2e28854939acde2d003f7984f721eba450b56a200ad90eeb0e6b"},
+ {file = "cryptography-46.0.5-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d7e3d356b8cd4ea5aff04f129d5f66ebdc7b6f8eae802b93739ed520c47c79b"},
+ {file = "cryptography-46.0.5-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:50bfb6925eff619c9c023b967d5b77a54e04256c4281b0e21336a130cd7fc263"},
+ {file = "cryptography-46.0.5-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:803812e111e75d1aa73690d2facc295eaefd4439be1023fefc4995eaea2af90d"},
+ {file = "cryptography-46.0.5-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ee190460e2fbe447175cda91b88b84ae8322a104fc27766ad09428754a618ed"},
+ {file = "cryptography-46.0.5-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:f145bba11b878005c496e93e257c1e88f154d278d2638e6450d17e0f31e558d2"},
+ {file = "cryptography-46.0.5-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:e9251e3be159d1020c4030bd2e5f84d6a43fe54b6c19c12f51cde9542a2817b2"},
+ {file = "cryptography-46.0.5-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:47fb8a66058b80e509c47118ef8a75d14c455e81ac369050f20ba0d23e77fee0"},
+ {file = "cryptography-46.0.5-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:4c3341037c136030cb46e4b1e17b7418ea4cbd9dd207e4a6f3b2b24e0d4ac731"},
+ {file = "cryptography-46.0.5-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:890bcb4abd5a2d3f852196437129eb3667d62630333aacc13dfd470fad3aaa82"},
+ {file = "cryptography-46.0.5-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:80a8d7bfdf38f87ca30a5391c0c9ce4ed2926918e017c29ddf643d0ed2778ea1"},
+ {file = "cryptography-46.0.5-cp311-abi3-win32.whl", hash = "sha256:60ee7e19e95104d4c03871d7d7dfb3d22ef8a9b9c6778c94e1c8fcc8365afd48"},
+ {file = "cryptography-46.0.5-cp311-abi3-win_amd64.whl", hash = "sha256:38946c54b16c885c72c4f59846be9743d699eee2b69b6988e0a00a01f46a61a4"},
+ {file = "cryptography-46.0.5-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:94a76daa32eb78d61339aff7952ea819b1734b46f73646a07decb40e5b3448e2"},
+ {file = "cryptography-46.0.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5be7bf2fb40769e05739dd0046e7b26f9d4670badc7b032d6ce4db64dddc0678"},
+ {file = "cryptography-46.0.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe346b143ff9685e40192a4960938545c699054ba11d4f9029f94751e3f71d87"},
+ {file = "cryptography-46.0.5-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:c69fd885df7d089548a42d5ec05be26050ebcd2283d89b3d30676eb32ff87dee"},
+ {file = "cryptography-46.0.5-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:8293f3dea7fc929ef7240796ba231413afa7b68ce38fd21da2995549f5961981"},
+ {file = "cryptography-46.0.5-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:1abfdb89b41c3be0365328a410baa9df3ff8a9110fb75e7b52e66803ddabc9a9"},
+ {file = "cryptography-46.0.5-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:d66e421495fdb797610a08f43b05269e0a5ea7f5e652a89bfd5a7d3c1dee3648"},
+ {file = "cryptography-46.0.5-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:4e817a8920bfbcff8940ecfd60f23d01836408242b30f1a708d93198393a80b4"},
+ {file = "cryptography-46.0.5-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:68f68d13f2e1cb95163fa3b4db4bf9a159a418f5f6e7242564fc75fcae667fd0"},
+ {file = "cryptography-46.0.5-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:a3d1fae9863299076f05cb8a778c467578262fae09f9dc0ee9b12eb4268ce663"},
+ {file = "cryptography-46.0.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c4143987a42a2397f2fc3b4d7e3a7d313fbe684f67ff443999e803dd75a76826"},
+ {file = "cryptography-46.0.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:7d731d4b107030987fd61a7f8ab512b25b53cef8f233a97379ede116f30eb67d"},
+ {file = "cryptography-46.0.5-cp314-cp314t-win32.whl", hash = "sha256:c3bcce8521d785d510b2aad26ae2c966092b7daa8f45dd8f44734a104dc0bc1a"},
+ {file = "cryptography-46.0.5-cp314-cp314t-win_amd64.whl", hash = "sha256:4d8ae8659ab18c65ced284993c2265910f6c9e650189d4e3f68445ef82a810e4"},
+ {file = "cryptography-46.0.5-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:4108d4c09fbbf2789d0c926eb4152ae1760d5a2d97612b92d508d96c861e4d31"},
+ {file = "cryptography-46.0.5-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1f30a86d2757199cb2d56e48cce14deddf1f9c95f1ef1b64ee91ea43fe2e18"},
+ {file = "cryptography-46.0.5-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:039917b0dc418bb9f6edce8a906572d69e74bd330b0b3fea4f79dab7f8ddd235"},
+ {file = "cryptography-46.0.5-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:ba2a27ff02f48193fc4daeadf8ad2590516fa3d0adeeb34336b96f7fa64c1e3a"},
+ {file = "cryptography-46.0.5-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:61aa400dce22cb001a98014f647dc21cda08f7915ceb95df0c9eaf84b4b6af76"},
+ {file = "cryptography-46.0.5-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3ce58ba46e1bc2aac4f7d9290223cead56743fa6ab94a5d53292ffaac6a91614"},
+ {file = "cryptography-46.0.5-cp38-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:420d0e909050490d04359e7fdb5ed7e667ca5c3c402b809ae2563d7e66a92229"},
+ {file = "cryptography-46.0.5-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:582f5fcd2afa31622f317f80426a027f30dc792e9c80ffee87b993200ea115f1"},
+ {file = "cryptography-46.0.5-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:bfd56bb4b37ed4f330b82402f6f435845a5f5648edf1ad497da51a8452d5d62d"},
+ {file = "cryptography-46.0.5-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:a3d507bb6a513ca96ba84443226af944b0f7f47dcc9a399d110cd6146481d24c"},
+ {file = "cryptography-46.0.5-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9f16fbdf4da055efb21c22d81b89f155f02ba420558db21288b3d0035bafd5f4"},
+ {file = "cryptography-46.0.5-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:ced80795227d70549a411a4ab66e8ce307899fad2220ce5ab2f296e687eacde9"},
+ {file = "cryptography-46.0.5-cp38-abi3-win32.whl", hash = "sha256:02f547fce831f5096c9a567fd41bc12ca8f11df260959ecc7c3202555cc47a72"},
+ {file = "cryptography-46.0.5-cp38-abi3-win_amd64.whl", hash = "sha256:556e106ee01aa13484ce9b0239bca667be5004efb0aabbed28d353df86445595"},
+ {file = "cryptography-46.0.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:3b4995dc971c9fb83c25aa44cf45f02ba86f71ee600d81091c2f0cbae116b06c"},
+ {file = "cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:bc84e875994c3b445871ea7181d424588171efec3e185dced958dad9e001950a"},
+ {file = "cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:2ae6971afd6246710480e3f15824ed3029a60fc16991db250034efd0b9fb4356"},
+ {file = "cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:d861ee9e76ace6cf36a6a89b959ec08e7bc2493ee39d07ffe5acb23ef46d27da"},
+ {file = "cryptography-46.0.5-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:2b7a67c9cd56372f3249b39699f2ad479f6991e62ea15800973b956f4b73e257"},
+ {file = "cryptography-46.0.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:8456928655f856c6e1533ff59d5be76578a7157224dbd9ce6872f25055ab9ab7"},
+ {file = "cryptography-46.0.5.tar.gz", hash = "sha256:abace499247268e3757271b2f1e244b36b06f8515cf27c4d49468fc9eb16e93d"},
]
[package.dependencies]
@@ -471,7 +466,7 @@ nox = ["nox[uv] (>=2024.4.15)"]
pep8test = ["check-sdist", "click (>=8.0.1)", "mypy (>=1.14)", "ruff (>=0.11.11)"]
sdist = ["build (>=1.0.0)"]
ssh = ["bcrypt (>=3.1.5)"]
-test = ["certifi (>=2024)", "cryptography-vectors (==46.0.3)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"]
+test = ["certifi (>=2024)", "cryptography-vectors (==46.0.5)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"]
test-randomorder = ["pytest-randomly"]
[[package]]
From 27b2915606dfb0fc55ccb063227747eb0816f641 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 17 Feb 2026 13:55:06 +0100
Subject: [PATCH 07/19] Bump tokio from 1.48.0 to 1.49.0 (#19443)
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.48.0 to 1.49.0.
Release notes
Sourced from tokio's
releases.
Tokio v1.49.0
1.49.0 (January 3rd, 2026)
Added
- net: add support for
TCLASS option on IPv6 (#7781)
- runtime: stabilize
runtime::id::Id (#7125)
- task: implement
Extend for JoinSet (#7195)
- task: stabilize the
LocalSet::id() (#7776)
Changed
- net: deprecate
{TcpStream,TcpSocket}::set_linger (#7752)
Fixed
- macros: fix the hygiene issue of
join! and
try_join! (#7766)
- runtime: revert "replace manual vtable definitions with
Wake" (#7699)
- sync: return
TryRecvError::Disconnected from
Receiver::try_recv after Receiver::close (#7686)
- task: remove unnecessary trait bounds on the
Debug
implementation (#7720)
Unstable
- fs: handle
EINTR in fs::write for io-uring
(#7786)
- fs: support io-uring with
tokio::fs::read (#7696)
- runtime: disable io-uring on
EPERM (#7724)
- time: add alternative timer for better multicore scalability (#7467)
Documented
- docs: fix a typos in
bounded.rs and
park.rs (#7817)
- io: add
SyncIoBridge cross-references to
copy and copy_buf (#7798)
- io: doc that
AsyncWrite does not inherit from
std::io::Write (#7705)
- metrics: clarify that
num_alive_tasks is not strongly
consistent (#7614)
- net: clarify the cancellation safety of the
TcpStream::peek (#7305)
- net: clarify the drop behavior of
unix::OwnedWriteHalf
(#7742)
- net: clarify the platform-dependent backlog in
TcpSocket docs (#7738)
- runtime: mention
LocalRuntime in
new_current_thread docs (#7820)
- sync: add missing period to
mpsc::Sender::try_send docs
(#7721)
- sync: clarify the cancellation safety of
oneshot::Receiver (#7780)
- sync: improve the docs for the
errors of mpsc (#7722)
- task: add example for
spawn_local usage on local
runtime (#7689)
#7125:
tokio-rs/tokio#7125
#7195:
tokio-rs/tokio#7195
#7305:
tokio-rs/tokio#7305
#7467:
tokio-rs/tokio#7467
#7614:
tokio-rs/tokio#7614
#7686:
tokio-rs/tokio#7686
#7689:
tokio-rs/tokio#7689
... (truncated)
Commits
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
Cargo.lock | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index e1344f89d6..c981d139d4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1416,9 +1416,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
-version = "1.48.0"
+version = "1.49.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408"
+checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86"
dependencies = [
"bytes",
"libc",
From 5be475f5a24b01df8e652838967b2809b78c6a43 Mon Sep 17 00:00:00 2001
From: Quentin Gliech
Date: Tue, 17 Feb 2026 13:57:14 +0100
Subject: [PATCH 08/19] Allow configuring the Rust HTTP client to use HTTP/2
only (#19457)
This allows the Rust HTTP client to be configured to force HTTP/2 even
on plaintext connections. This is useful in contexts where the remote
server is known to server HTTP/2 over plain text.
Added because we use the Synapse Rust HTTP client with the Synapse Pro
`event-cache` module. We use this because it's independent from the
Python reactor which makes things slower than expected.
Currently, the Synapse Rust HTTP client uses HTTP/1 which means a new
connection for every request. With HTTP/2, we can share the connection
across requests.
We want to see if this will make a performance difference and less
stress on the database connection situation, see
https://github.com/element-hq/synapse-rust-apps/issues/452#issuecomment-3897717599
Here is the sibling PR for using HTTP/2 on the Synapse Pro `event-cache`
module side: https://github.com/element-hq/synapse-pro-modules/pull/35
---
changelog.d/19457.misc | 1 +
rust/src/http_client.rs | 22 +++++++++++++++++-----
synapse/synapse_rust/http_client.pyi | 20 +++++++++++++++++++-
3 files changed, 37 insertions(+), 6 deletions(-)
create mode 100644 changelog.d/19457.misc
diff --git a/changelog.d/19457.misc b/changelog.d/19457.misc
new file mode 100644
index 0000000000..ccbb7f5b14
--- /dev/null
+++ b/changelog.d/19457.misc
@@ -0,0 +1 @@
+Allow configuring the Rust HTTP client to use HTTP/2 only.
diff --git a/rust/src/http_client.rs b/rust/src/http_client.rs
index b1e4f753b8..9bbdff8b45 100644
--- a/rust/src/http_client.rs
+++ b/rust/src/http_client.rs
@@ -171,15 +171,27 @@ struct HttpClient {
#[pymethods]
impl HttpClient {
#[new]
- pub fn py_new(reactor: Bound, user_agent: &str) -> PyResult {
+ #[pyo3(signature = (reactor, user_agent, http2_only = false))]
+ pub fn py_new(
+ reactor: Bound,
+ user_agent: &str,
+ http2_only: bool,
+ ) -> PyResult {
// Make sure the runtime gets installed
let _ = runtime(&reactor)?;
+ let mut builder = reqwest::Client::builder().user_agent(user_agent);
+
+ if http2_only {
+ // Create the client with 'HTTP/2 prior knowledge' enabled, which
+ // means it will always use HTTP/2 for unencrypted connections
+ builder = builder.http2_prior_knowledge();
+ }
+
+ let client = builder.build().context("building reqwest client")?;
+
Ok(HttpClient {
- client: reqwest::Client::builder()
- .user_agent(user_agent)
- .build()
- .context("building reqwest client")?,
+ client,
reactor: reactor.unbind(),
})
}
diff --git a/synapse/synapse_rust/http_client.pyi b/synapse/synapse_rust/http_client.pyi
index 530d2be8e3..1814daec73 100644
--- a/synapse/synapse_rust/http_client.pyi
+++ b/synapse/synapse_rust/http_client.pyi
@@ -21,7 +21,25 @@ class HttpClient:
The returned deferreds follow Synapse logcontext rules.
"""
- def __init__(self, reactor: ISynapseReactor, user_agent: str) -> None: ...
+ def __init__(
+ self,
+ reactor: ISynapseReactor,
+ user_agent: str,
+ http2_only: bool = False,
+ ) -> None:
+ """
+ Create a new HTTP client backed by reqwest.
+
+ Args:
+ reactor: The Twisted reactor to coordinate with
+ user_agent: The user agent to use for requests
+ http2_only: Whether to use HTTP/2 only, even on unencrypted connections. By
+ default, it will always use HTTP/1.1 over unencrypted connections, and
+ rely on TLS ALPN to negotiate HTTP/2.
+
+ Ensure the upstream server supports HTTP/2 before enabling this.
+ """
+
def get(self, url: str, response_limit: int) -> Deferred[bytes]: ...
def post(
self,
From 1592afba8d6d8421febe93162565edede48c9992 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 17 Feb 2026 13:58:10 +0100
Subject: [PATCH 09/19] Bump github.com/docker/docker from 28.2.2+incompatible
to 28.3.3+incompatible in /complement (#19436)
Bumps [github.com/docker/docker](https://github.com/docker/docker) from
28.2.2+incompatible to 28.3.3+incompatible.
Release notes
Sourced from github.com/docker/docker's
releases.
v28.3.3
28.3.3
For a full list of pull requests and changes in this release, refer
to the relevant GitHub milestones:
Security
This release fixes an issue where, after a firewalld reload,
published container ports could be accessed directly from the local
network, even when they were intended to be accessible only via a
loopback address. CVE-2025-54388
/ GHSA-x4rx-4gw3-53p4
/ moby/moby#50506.
Packaging updates
Go SDK
- cli/command/formatter: add
TrunateID() utility as
alternative for
github.com/docker/docker/pkg/stringid.TrunateID(). docker/cli#6180
28.3.2
For a full list of pull requests and changes in this release, refer
to the relevant GitHub milestones:
Bug fixes and enhancements
- Fix
--use-api-socket not working correctly when
targeting a remote daemon. docker/cli#6157
- Fix stray "otel error" logs being printed if debug logging
is enabled. docker/cli#6160
- Quote SSH arguments when connecting to a remote daemon over an SSH
connection to avoid unexpected expansion. docker/cli#6147
- Warn when
DOCKER_AUTH_CONFIG is set during docker
login and docker logout. docker/cli#6163
Packaging updates
28.3.1
For a full list of pull requests and changes in this release, refer
to the relevant GitHub milestones:
... (truncated)
Commits
bea959c
Merge pull request #50506
from robmry/backport-28.x/fix_firewalld_reload
3e9ff78
bridge: Reapply endpoint iptables rules on firewalld reload
29ed80a
bridge: Trigger firewalld reload during bridge integration tests
da489a1
Merge pull request #50478
from thaJeztah/28.x_backport_gha_bump_bk
f173e45
Merge pull request #50480
from austinvazquez/cherry-pick-ea29dffaa541289591aa...
e4b1f89
daemon/server: remove compatibility with API v1.4 auth-config on
push
0c9e14d
hack/buildkit-ref: temporarily bump BuildKit to head of v0.23
branch
bf6d688
Merge pull request #50471
from austinvazquez/cherry-pick-b1ce0c89f0214cc6711c...
4205776
client: always send (empty) body on push
e77ff99
Merge pull request #50354
from vvoland/50353-28.x
- Additional commits viewable in compare
view
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/element-hq/synapse/network/alerts).
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
complement/go.mod | 158 +----------------
complement/go.sum | 422 +---------------------------------------------
2 files changed, 5 insertions(+), 575 deletions(-)
diff --git a/complement/go.mod b/complement/go.mod
index 062ea8e6ee..c6c1678bac 100644
--- a/complement/go.mod
+++ b/complement/go.mod
@@ -5,171 +5,44 @@ go 1.24.1
toolchain go1.24.4
require (
- github.com/docker/docker v28.2.2+incompatible
- github.com/docker/go-connections v0.5.0
github.com/matrix-org/complement v0.0.0-20251120181401-44111a2a8a9d
github.com/matrix-org/gomatrixserverlib v0.0.0-20250813150445-9f5070a65744
- github.com/minio/operator v0.0.0-20250423184541-6eee6a7caa70
- github.com/mittwald/go-helm-client v0.12.18
- gopkg.in/yaml.v2 v2.4.0
- k8s.io/api v0.33.2
- k8s.io/apimachinery v0.33.2
- k8s.io/client-go v0.33.2
- sigs.k8s.io/controller-runtime v0.21.0
)
require (
- github.com/cloudnative-pg/barman-cloud v0.3.1 // indirect
- github.com/cloudnative-pg/machinery v0.2.0 // indirect
- github.com/dustin/go-humanize v1.0.1 // indirect
- github.com/evanphx/json-patch/v5 v5.9.11 // indirect
- github.com/fsnotify/fsnotify v1.8.0 // indirect
- github.com/go-ini/ini v1.67.0 // indirect
- github.com/go-logr/zapr v1.3.0 // indirect
- github.com/go-ole/go-ole v1.3.0 // indirect
- github.com/goccy/go-json v0.10.5 // indirect
- github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
- github.com/golang/protobuf v1.5.4 // indirect
+ github.com/docker/docker v28.3.3+incompatible // indirect
+ github.com/docker/go-connections v0.5.0 // indirect
github.com/hashicorp/go-set/v3 v3.0.0 // indirect
- github.com/klauspost/cpuid/v2 v2.2.10 // indirect
- github.com/kubernetes-csi/external-snapshotter/client/v8 v8.2.0 // indirect
- github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 // indirect
- github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530 // indirect
- github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
- github.com/miekg/dns v1.1.66 // indirect
- github.com/minio/crc64nvme v1.0.1 // indirect
- github.com/minio/madmin-go/v3 v3.0.100 // indirect
- github.com/minio/md5-simd v1.1.2 // indirect
- github.com/minio/minio-go/v7 v7.0.89 // indirect
github.com/moby/sys/atomicwriter v0.1.0 // indirect
github.com/oleiade/lane/v2 v2.0.0 // indirect
- github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c // indirect
- github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
- github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.80.1 // indirect
- github.com/prometheus/prom2json v1.4.1 // indirect
- github.com/prometheus/prometheus v0.302.1 // indirect
- github.com/rs/xid v1.6.0 // indirect
- github.com/safchain/ethtool v0.5.10 // indirect
- github.com/secure-io/sio-go v0.3.1 // indirect
- github.com/shirou/gopsutil/v3 v3.24.5 // indirect
- github.com/shoenig/go-m1cpu v0.1.6 // indirect
- github.com/tinylib/msgp v1.2.5 // indirect
- github.com/tklauser/go-sysconf v0.3.15 // indirect
- github.com/tklauser/numcpus v0.10.0 // indirect
- github.com/yusufpapurcu/wmi v1.2.4 // indirect
- go.uber.org/multierr v1.11.0 // indirect
- go.uber.org/zap v1.27.0 // indirect
+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0 // indirect
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
- golang.org/x/mod v0.29.0 // indirect
- golang.org/x/tools v0.38.0 // indirect
- gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
gotest.tools/v3 v3.4.0 // indirect
- oras.land/oras-go/v2 v2.6.0 // indirect
)
require (
- dario.cat/mergo v1.0.1 // indirect
- github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
- github.com/BurntSushi/toml v1.5.0 // indirect
- github.com/MakeNowJust/heredoc v1.0.0 // indirect
- github.com/Masterminds/goutils v1.1.1 // indirect
- github.com/Masterminds/semver/v3 v3.3.1 // indirect
- github.com/Masterminds/sprig/v3 v3.3.0 // indirect
- github.com/Masterminds/squirrel v1.5.4 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
- github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
- github.com/beorn7/perks v1.0.1 // indirect
- github.com/blang/semver/v4 v4.0.0 // indirect
- github.com/cespare/xxhash/v2 v2.3.0 // indirect
- github.com/chai2010/gettext-go v1.0.2 // indirect
- github.com/cloudnative-pg/cloudnative-pg v1.26.0
- github.com/containerd/containerd v1.7.27 // indirect
github.com/containerd/errdefs v1.0.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect
- github.com/containerd/log v0.1.0 // indirect
- github.com/containerd/platforms v0.2.1 // indirect
- github.com/cyphar/filepath-securejoin v0.4.1 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
- github.com/emicklei/go-restful/v3 v3.12.2 // indirect
- github.com/evanphx/json-patch v5.9.11+incompatible // indirect
- github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect
- github.com/fatih/color v1.18.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
- github.com/fxamacker/cbor/v2 v2.7.0 // indirect
- github.com/go-errors/errors v1.5.1 // indirect
- github.com/go-gorp/gorp/v3 v3.1.0 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
- github.com/go-openapi/jsonpointer v0.21.1 // indirect
- github.com/go-openapi/jsonreference v0.21.0 // indirect
- github.com/go-openapi/swag v0.23.1 // indirect
- github.com/gobwas/glob v0.2.3 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
- github.com/google/btree v1.1.3 // indirect
- github.com/google/gnostic-models v0.6.9 // indirect
- github.com/google/go-cmp v0.7.0 // indirect
- github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
- github.com/google/uuid v1.6.0 // indirect
- github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
- github.com/gosuri/uitable v0.0.4 // indirect
- github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
- github.com/hashicorp/errwrap v1.1.0 // indirect
- github.com/hashicorp/go-multierror v1.1.1 // indirect
- github.com/huandu/xstrings v1.5.0 // indirect
- github.com/inconshreveable/mousetrap v1.1.0 // indirect
- github.com/jmoiron/sqlx v1.4.0 // indirect
- github.com/josharian/intern v1.0.0 // indirect
- github.com/json-iterator/go v1.1.12 // indirect
- github.com/klauspost/compress v1.18.0 // indirect
- github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
- github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
- github.com/lib/pq v1.10.9 // indirect
- github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
- github.com/mailru/easyjson v0.9.0 // indirect
github.com/matrix-org/util v0.0.0-20221111132719-399730281e66 // indirect
- github.com/mattn/go-colorable v0.1.14 // indirect
- github.com/mattn/go-isatty v0.0.20 // indirect
- github.com/mattn/go-runewidth v0.0.15 // indirect
- github.com/mitchellh/copystructure v1.2.0 // indirect
- github.com/mitchellh/go-wordwrap v1.0.1 // indirect
- github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
- github.com/moby/spdystream v0.5.0 // indirect
github.com/moby/term v0.5.2 // indirect
- github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
- github.com/modern-go/reflect2 v1.0.2 // indirect
- github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
- github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
- github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
- github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
- github.com/prometheus/client_golang v1.22.0 // indirect
- github.com/prometheus/client_model v0.6.2
- github.com/prometheus/common v0.65.0
- github.com/prometheus/procfs v0.16.0 // indirect
- github.com/rivo/uniseg v0.4.4 // indirect
- github.com/rubenv/sql-migrate v1.8.0 // indirect
- github.com/russross/blackfriday/v2 v2.1.0 // indirect
- github.com/shopspring/decimal v1.4.0 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
- github.com/spf13/cast v1.7.0 // indirect
- github.com/spf13/cobra v1.9.1 // indirect
- github.com/spf13/pflag v1.0.6 // indirect
- github.com/stretchr/testify v1.10.0
github.com/tidwall/gjson v1.18.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tidwall/sjson v1.2.5 // indirect
- github.com/x448/float16 v0.8.4 // indirect
- github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
- github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
- github.com/xeipuuv/gojsonschema v1.2.0 // indirect
- github.com/xlab/treeprint v1.2.0 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
go.opentelemetry.io/otel v1.36.0 // indirect
@@ -178,32 +51,7 @@ require (
go.opentelemetry.io/otel/trace v1.36.0 // indirect
go.opentelemetry.io/proto/otlp v1.7.0 // indirect
golang.org/x/crypto v0.45.0 // indirect
- golang.org/x/net v0.47.0 // indirect
- golang.org/x/oauth2 v0.30.0 // indirect
- golang.org/x/sync v0.18.0 // indirect
golang.org/x/sys v0.38.0 // indirect
- golang.org/x/term v0.37.0 // indirect
- golang.org/x/text v0.31.0 // indirect
golang.org/x/time v0.11.0 // indirect
- google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect
- google.golang.org/grpc v1.72.2 // indirect
google.golang.org/protobuf v1.36.6 // indirect
- gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
- gopkg.in/inf.v0 v0.9.1 // indirect
- gopkg.in/yaml.v3 v3.0.1 // indirect
- helm.sh/helm/v3 v3.18.4 // indirect
- k8s.io/apiextensions-apiserver v0.33.2 // indirect
- k8s.io/apiserver v0.33.2 // indirect
- k8s.io/cli-runtime v0.33.2 // indirect
- k8s.io/component-base v0.33.2 // indirect
- k8s.io/klog/v2 v2.130.1
- k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
- k8s.io/kubectl v0.33.2 // indirect
- k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979 // indirect
- sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
- sigs.k8s.io/kustomize/api v0.19.0 // indirect
- sigs.k8s.io/kustomize/kyaml v0.19.0 // indirect
- sigs.k8s.io/randfill v1.0.0 // indirect
- sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect
- sigs.k8s.io/yaml v1.4.0 // indirect
)
diff --git a/complement/go.sum b/complement/go.sum
index 2ff8608953..c674730c05 100644
--- a/complement/go.sum
+++ b/complement/go.sum
@@ -1,228 +1,47 @@
-dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
-dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
-filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
-filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
-github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU=
-github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
-github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
-github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
-github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU=
-github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
-github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
-github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
-github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
-github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
-github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4=
-github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
-github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs=
-github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0=
-github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM=
-github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10=
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
-github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
-github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
-github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so=
-github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
-github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
-github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
-github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
-github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
-github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70=
-github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
-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/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk=
-github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA=
-github.com/cloudnative-pg/barman-cloud v0.3.1 h1:kzkY77k2lN/caoyh7ibXDSZjJeSJTNvnVt6Gfa8Iq5M=
-github.com/cloudnative-pg/barman-cloud v0.3.1/go.mod h1:4HL3AjY9oEl2Ed0HSkyvTZEQPhwyFOaAnuCz9lfVeYQ=
-github.com/cloudnative-pg/cloudnative-pg v1.26.0 h1:X+ayWg6TXqglziSPejKiviPTf/CSh4AmYXx1mrS3i8s=
-github.com/cloudnative-pg/cloudnative-pg v1.26.0/go.mod h1:aNh0g7UHKxyka4HYOqLaYDWtZ6tORQ7HbIHLvb79sx8=
-github.com/cloudnative-pg/machinery v0.2.0 h1:x8OAwxdeL/6wkbxqorz+nX6UovTyx7/TBeCfiRebR2o=
-github.com/cloudnative-pg/machinery v0.2.0/go.mod h1:Kg8W8Tb/1UFGGtw3hR8S5SytSWddlHaCnJSgBo4x/nc=
-github.com/containerd/containerd v1.7.27 h1:yFyEyojddO3MIGVER2xJLWoCIn+Up4GaHFquP7hsFII=
-github.com/containerd/containerd v1.7.27/go.mod h1:xZmPnl75Vc+BLGt4MIfu6bp+fy03gdHAn9bz+FreFR0=
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
-github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
-github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=
-github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
-github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
-github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
-github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
-github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
-github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
-github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
-github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
-github.com/distribution/distribution/v3 v3.0.0 h1:q4R8wemdRQDClzoNNStftB2ZAfqOiN6UX90KJc4HjyM=
-github.com/distribution/distribution/v3 v3.0.0/go.mod h1:tRNuFoZsUdyRVegq8xGNeds4KLjwLCRin/tTo6i1DhU=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
-github.com/docker/docker v28.2.2+incompatible h1:CjwRSksz8Yo4+RmQ339Dp/D2tGO5JxwYeqtMOEe0LDw=
-github.com/docker/docker v28.2.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
-github.com/docker/docker-credential-helpers v0.9.3 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqIjCBS4wrsOh9yRqcz8=
-github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo=
+github.com/docker/docker v28.3.3+incompatible h1:Dypm25kh4rmk49v1eiVbsAtpAsYURjYkaKubwuBdxEI=
+github.com/docker/docker v28.3.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
-github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8=
-github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA=
-github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8=
-github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
-github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
-github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
-github.com/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU=
-github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
-github.com/evanphx/json-patch v5.9.11+incompatible h1:ixHHqfcGvxhWkniF1tWxBHA0yb4Z+d1UQi45df52xW8=
-github.com/evanphx/json-patch v5.9.11+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
-github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU=
-github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM=
-github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4=
-github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc=
-github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
-github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
-github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7DlmewI=
-github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk=
-github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
-github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
-github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
-github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
-github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
-github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
-github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk=
-github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
-github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs=
-github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw=
-github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
-github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
-github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ=
-github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg=
-github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
-github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
-github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
-github.com/go-openapi/jsonpointer v0.21.1 h1:whnzv/pNXtK2FbX/W9yJfRmE2gsmkfahjMKB0fZvcic=
-github.com/go-openapi/jsonpointer v0.21.1/go.mod h1:50I1STOfbY1ycR8jGz8DaMeLCdXiI6aDteEdRNNzpdk=
-github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
-github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
-github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU=
-github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0=
-github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
-github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
-github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
-github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
-github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
-github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
-github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
-github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
-github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=
-github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
-github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
-github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
-github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
-github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
-github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw=
-github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
-github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
-github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8=
-github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
-github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
-github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE=
-github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w=
-github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
-github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
-github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
-github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
-github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY=
-github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo=
-github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
-github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
-github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
-github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
-github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
-github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
-github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
-github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
-github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
-github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/hashicorp/go-set/v3 v3.0.0 h1:CaJBQvQCOWoftrBcDt7Nwgo0kdpmrKxar/x2o6pV9JA=
github.com/hashicorp/go-set/v3 v3.0.0/go.mod h1:IEghM2MpE5IaNvL+D7X480dfNtxjRXZ6VMpK3C8s2ok=
-github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o8jga4=
-github.com/hashicorp/golang-lru/arc/v2 v2.0.5 h1:l2zaLDubNhW4XO3LnliVj0GXO3+/CGNJAg1dcN2Fpfw=
-github.com/hashicorp/golang-lru/arc/v2 v2.0.5/go.mod h1:ny6zBSQZi2JxIeYcv7kt2sH2PXJtirBN7RDhRpxPkxU=
-github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4=
-github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
-github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
-github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
-github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
-github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
-github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
-github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
-github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
-github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
-github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
-github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
-github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
-github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
-github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
-github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
-github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
-github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
-github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
-github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/kubernetes-csi/external-snapshotter/client/v8 v8.2.0 h1:Q3jQ1NkFqv5o+F8dMmHd8SfEmlcwNeo1immFApntEwE=
-github.com/kubernetes-csi/external-snapshotter/client/v8 v8.2.0/go.mod h1:E3vdYxHj2C2q6qo8/Da4g7P+IcwqRZyy3gJBzYybV9Y=
-github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
-github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
-github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw=
-github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
-github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk=
-github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
-github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
-github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
-github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
-github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
-github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 h1:PpXWgLPs+Fqr325bN2FD2ISlRRztXibcX6e8f5FR5Dc=
-github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35/go.mod h1:autxFIvghDt3jPTLoqZ9OZ7s9qTGNAWmYCjVFWPX/zg=
-github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
-github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
github.com/matrix-org/complement v0.0.0-20251120181401-44111a2a8a9d h1:s2Xc9GB2E/pXdElP18h8+04Y3SmhaII7xh2YmCM7oZc=
github.com/matrix-org/complement v0.0.0-20251120181401-44111a2a8a9d/go.mod h1:HioTV089DHLBfljH9QLGifJRE4Avnyk08BXXhCwd4gs=
github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530 h1:kHKxCOLcHH8r4Fzarl4+Y3K5hjothkVW5z7T1dUM11U=
@@ -231,148 +50,35 @@ github.com/matrix-org/gomatrixserverlib v0.0.0-20250813150445-9f5070a65744 h1:5G
github.com/matrix-org/gomatrixserverlib v0.0.0-20250813150445-9f5070a65744/go.mod h1:b6KVfDjXjA5Q7vhpOaMqIhFYvu5BuFVZixlNeTV/CLc=
github.com/matrix-org/util v0.0.0-20221111132719-399730281e66 h1:6z4KxomXSIGWqhHcfzExgkH3Z3UkIXry4ibJS4Aqz2Y=
github.com/matrix-org/util v0.0.0-20221111132719-399730281e66/go.mod h1:iBI1foelCqA09JJgPV0FYz4qA5dUXYOxMi57FxKBdd4=
-github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
-github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
-github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
-github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
-github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
-github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
-github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
-github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
-github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
-github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
-github.com/miekg/dns v1.1.66 h1:FeZXOS3VCVsKnEAd+wBkjMC3D2K+ww66Cq3VnCINuJE=
-github.com/miekg/dns v1.1.66/go.mod h1:jGFzBsSNbJw6z1HYut1RKBKHA9PBdxeHrZG8J+gC2WE=
-github.com/minio/crc64nvme v1.0.1 h1:DHQPrYPdqK7jQG/Ls5CTBZWeex/2FMS3G5XGkycuFrY=
-github.com/minio/crc64nvme v1.0.1/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg=
-github.com/minio/madmin-go/v3 v3.0.100 h1:1gsy1kHgk8v9ZQyEU/L9k1ZoImFid+hlzwrOgUULB88=
-github.com/minio/madmin-go/v3 v3.0.100/go.mod h1:pMLdj9OtN0CANNs5tdm6opvOlDFfj0WhbztboZAjRWE=
-github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
-github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
-github.com/minio/minio-go/v7 v7.0.89 h1:hx4xV5wwTUfyv8LarhJAwNecnXpoTsj9v3f3q/ZkiJU=
-github.com/minio/minio-go/v7 v7.0.89/go.mod h1:2rFnGAp02p7Dddo1Fq4S2wYOfpF0MUTSeLTRC90I204=
-github.com/minio/operator v0.0.0-20250423184541-6eee6a7caa70 h1:CTpACn2vNMA76TXKGufGhxVa9KIw3Qdvtx6j/l5fKeE=
-github.com/minio/operator v0.0.0-20250423184541-6eee6a7caa70/go.mod h1:NL8ANdLUtI70DmG2x2EMCfoe6d3ijD1Xok/N1Tr8Czo=
-github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
-github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
-github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
-github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
-github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
-github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
-github.com/mittwald/go-helm-client v0.12.18 h1:i9cJNv/YC3ZPKUKVNYTlrOO7ZO6YFKE/ak3J5TeYHPU=
-github.com/mittwald/go-helm-client v0.12.18/go.mod h1:dLl5NkdKCvwKvLIdZzg4MDbxhSKmuimdmM3WpsAzS0I=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
-github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU=
-github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=
github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs=
github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
-github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
-github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
-github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
-github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
-github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
-github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
-github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
-github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
-github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/oleiade/lane/v2 v2.0.0 h1:XW/ex/Inr+bPkLd3O240xrFOhUkTd4Wy176+Gv0E3Qw=
github.com/oleiade/lane/v2 v2.0.0/go.mod h1:i5FBPFAYSWCgLh58UkUGCChjcCzef/MI7PlQm2TKCeg=
-github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus=
-github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8=
-github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y=
-github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
-github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
-github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
-github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI=
-github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE=
-github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c h1:dAMKvw0MlJT1GshSTtih8C2gDs04w8dReiOGXrGLNoY=
-github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
-github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
-github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY=
-github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg=
-github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.80.1 h1:DP+PUNVOc+Bkft8a4QunLzaZ0RspWuD3tBbcPHr2PeE=
-github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.80.1/go.mod h1:6x4x0t9BP35g4XcjkHE9EB3RxhyfxpdpmZKd/Qyk8+M=
-github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
-github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
-github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
-github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
-github.com/prometheus/common v0.65.0 h1:QDwzd+G1twt//Kwj/Ww6E9FQq1iVMmODnILtW1t2VzE=
-github.com/prometheus/common v0.65.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8=
-github.com/prometheus/procfs v0.16.0 h1:xh6oHhKwnOJKMYiYBDWmkHqQPyiY40sny36Cmx2bbsM=
-github.com/prometheus/procfs v0.16.0/go.mod h1:8veyXUu3nGP7oaCxhX6yeaM5u4stL2FeMXnCqhDthZg=
-github.com/prometheus/prom2json v1.4.1 h1:7McxdrHgPEOtMwWjkKtd0v5AhpR2Q6QAnlHKVxq0+tQ=
-github.com/prometheus/prom2json v1.4.1/go.mod h1:CzOQykSKFxXuC7ELUZHOHQvwKesQ3eN0p2PWLhFitQM=
-github.com/prometheus/prometheus v0.302.1 h1:xqVdrwrB4WNpdgJqxsz5loqFWNUZitsK8myqLuSZ6Ag=
-github.com/prometheus/prometheus v0.302.1/go.mod h1:YcyCoTbUR/TM8rY3Aoeqr0AWTu/pu1Ehh+trpX3eRzg=
-github.com/redis/go-redis/extra/rediscmd/v9 v9.0.5 h1:EaDatTxkdHG+U3Bk4EUr+DZ7fOGwTfezUiUJMaIcaho=
-github.com/redis/go-redis/extra/rediscmd/v9 v9.0.5/go.mod h1:fyalQWdtzDBECAQFBJuQe5bzQ02jGd5Qcbgb97Flm7U=
-github.com/redis/go-redis/extra/redisotel/v9 v9.0.5 h1:EfpWLLCyXw8PSM2/XNJLjI3Pb27yVE+gIAfeqp8LUCc=
-github.com/redis/go-redis/extra/redisotel/v9 v9.0.5/go.mod h1:WZjPDy7VNzn77AAfnAfVjZNvfJTYfPetfZk5yoSTLaQ=
-github.com/redis/go-redis/v9 v9.7.3 h1:YpPyAayJV+XErNsatSElgRZZVCwXX9QzkKYNvO7x0wM=
-github.com/redis/go-redis/v9 v9.7.3/go.mod h1:bGUrSggJ9X9GUmZpZNEOQKaANxSGgOEBRltRTZHSvrA=
-github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
-github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
-github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
-github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
-github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
-github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
-github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
-github.com/rubenv/sql-migrate v1.8.0 h1:dXnYiJk9k3wetp7GfQbKJcPHjVJL6YK19tKj8t2Ns0o=
-github.com/rubenv/sql-migrate v1.8.0/go.mod h1:F2bGFBwCU+pnmbtNYDeKvSuvL6lBVtXDXUUv5t+u1qw=
-github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
-github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
-github.com/safchain/ethtool v0.5.10 h1:Im294gZtuf4pSGJRAOGKaASNi3wMeFaGaWuSaomedpc=
-github.com/safchain/ethtool v0.5.10/go.mod h1:w9jh2Lx7YBR4UwzLkzCmWl85UY0W2uZdd7/DckVE5+c=
-github.com/secure-io/sio-go v0.3.1 h1:dNvY9awjabXTYGsTF1PiCySl9Ltofk9GA3VdWlo7rRc=
-github.com/secure-io/sio-go v0.3.1/go.mod h1:+xbkjDzPjwh4Axd07pRKSNriS9SCiYksWnZqdnfpQxs=
-github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
-github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
-github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
-github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
-github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
-github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/shoenig/test v1.11.0 h1:NoPa5GIoBwuqzIviCrnUJa+t5Xb4xi5Z+zODJnIDsEQ=
github.com/shoenig/test v1.11.0/go.mod h1:UxJ6u/x2v/TNs/LoLxBNJRV9DiwBBKYxXSyczsBHFoI=
-github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
-github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
-github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
-github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
-github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
-github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
-github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
-github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
-github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
-github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
-github.com/thoas/go-funk v0.9.3 h1:7+nAEx3kn5ZJcnDm2Bh23N2yOtweO14bi//dvRtgLpw=
-github.com/thoas/go-funk v0.9.3/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q=
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
@@ -383,84 +89,30 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
-github.com/tinylib/msgp v1.2.5 h1:WeQg1whrXRFiZusidTQqzETkRpGjFjcIhW6uqWH09po=
-github.com/tinylib/msgp v1.2.5/go.mod h1:ykjzy2wzgrlvpDCRc4LA8UXy6D8bzMSuAF3WD57Gok0=
-github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4=
-github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4=
-github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso=
-github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ=
-github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
-github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
-github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
-github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
-github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
-github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
-github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
-github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
-github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
-github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ=
-github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
-github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
-go.opentelemetry.io/contrib/bridges/prometheus v0.57.0 h1:UW0+QyeyBVhn+COBec3nGhfnFe5lwB0ic1JBVjzhk0w=
-go.opentelemetry.io/contrib/bridges/prometheus v0.57.0/go.mod h1:ppciCHRLsyCio54qbzQv0E4Jyth/fLWDTJYfvWpcSVk=
-go.opentelemetry.io/contrib/exporters/autoexport v0.57.0 h1:jmTVJ86dP60C01K3slFQa2NQ/Aoi7zA+wy7vMOKD9H4=
-go.opentelemetry.io/contrib/exporters/autoexport v0.57.0/go.mod h1:EJBheUMttD/lABFyLXhce47Wr6DPWYReCzaZiXadH7g=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
-go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.8.0 h1:WzNab7hOOLzdDF/EoWCt4glhrbMPVMOO5JYTmpz36Ls=
-go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.8.0/go.mod h1:hKvJwTzJdp90Vh7p6q/9PAOd55dI6WA6sWj62a/JvSs=
-go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.8.0 h1:S+LdBGiQXtJdowoJoQPEtI52syEP/JYBUpjO49EQhV8=
-go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.8.0/go.mod h1:5KXybFvPGds3QinJWQT7pmXf+TN5YIa7CNYObWRkj50=
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.32.0 h1:j7ZSD+5yn+lo3sGV69nW04rRR0jhYnBwjuX3r0HvnK0=
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.32.0/go.mod h1:WXbYJTUaZXAbYd8lbgGuvih0yuCfOFC5RJoYnoLcGz8=
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.32.0 h1:t/Qur3vKSkUCcDVaSumWF2PKHt85pc7fRvFuoVT8qFU=
-go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.32.0/go.mod h1:Rl61tySSdcOJWoEgYZVtmnKdA0GeKrSqkHC1t+91CH8=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0 h1:dNzwXjZKpMpE2JhmO+9HsPl42NIXFIFSUSSs0fiqra0=
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0/go.mod h1:90PoxvaEB5n6AOdZvi+yWJQoE95U8Dhhw2bSyRqnTD0=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 h1:tgJ0uaNS4c98WRNUEx5U3aDlrDOI5Rs+1Vifcw4DJ8U=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0/go.mod h1:U7HYyW0zt/a9x5J1Kjs+r1f/d4ZHnYFclhYY2+YbeoE=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0 h1:BEj3SPM81McUZHYjRS5pEgNgnmzGJ5tRpU5krWnV8Bs=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.34.0/go.mod h1:9cKLGBDzI/F3NoHLQGm4ZrYdIHsvGt6ej6hUowxY0J4=
-go.opentelemetry.io/otel/exporters/prometheus v0.54.0 h1:rFwzp68QMgtzu9PgP3jm9XaMICI6TsofWWPcBDKwlsU=
-go.opentelemetry.io/otel/exporters/prometheus v0.54.0/go.mod h1:QyjcV9qDP6VeK5qPyKETvNjmaaEc7+gqjh4SS0ZYzDU=
-go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.8.0 h1:CHXNXwfKWfzS65yrlB2PVds1IBZcdsX8Vepy9of0iRU=
-go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.8.0/go.mod h1:zKU4zUgKiaRxrdovSS2amdM5gOc59slmo/zJwGX+YBg=
-go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.32.0 h1:SZmDnHcgp3zwlPBS2JX2urGYe/jBKEIT6ZedHRUyCz8=
-go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.32.0/go.mod h1:fdWW0HtZJ7+jNpTKUR0GpMEDP69nR8YBJQxNiVCE3jk=
-go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.32.0 h1:cC2yDI3IQd0Udsux7Qmq8ToKAx1XCilTQECZ0KDZyTw=
-go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.32.0/go.mod h1:2PD5Ex6z8CFzDbTdOlwyNIUywRr1DN0ospafJM1wJ+s=
-go.opentelemetry.io/otel/log v0.8.0 h1:egZ8vV5atrUWUbnSsHn6vB8R21G2wrKqNiDt3iWertk=
-go.opentelemetry.io/otel/log v0.8.0/go.mod h1:M9qvDdUTRCopJcGRKg57+JSQ9LgLBrwwfC32epk5NX8=
go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
-go.opentelemetry.io/otel/sdk/log v0.8.0 h1:zg7GUYXqxk1jnGF/dTdLPrK06xJdrXgqgFLnI4Crxvs=
-go.opentelemetry.io/otel/sdk/log v0.8.0/go.mod h1:50iXr0UVwQrYS45KbruFrEt4LvAdCaWWgIrsN3ZQggo=
go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
go.opentelemetry.io/proto/otlp v1.7.0 h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os=
go.opentelemetry.io/proto/otlp v1.7.0/go.mod h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo=
-go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
-go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
-go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
-go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
-go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
-go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
-go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
-go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
@@ -468,38 +120,22 @@ golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
-golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
-golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
-golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
-golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
-golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
-golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
-golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
@@ -511,15 +147,10 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
-golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
-golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw=
-gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
-google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 h1:KAeGQVN3M9nD0/bQXnr/ClcEMJ968gUXJQ9pwfSynuQ=
google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a h1:SGktgSolFCo75dnHJF2yMvnns6jCmHFJ0vE4Vn2JKvQ=
google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a/go.mod h1:a77HrdMjoeKbnd2jmgcWdaS++ZLZAEq3orIOAEIKiVw=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE=
@@ -529,14 +160,6 @@ google.golang.org/grpc v1.72.2/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3i
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
-gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=
-gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
-gopkg.in/h2non/gock.v1 v1.1.2 h1:jBbHXgGBK/AoPVfJh5x4r/WxIrElvbLel8TCZkkZJoY=
-gopkg.in/h2non/gock.v1 v1.1.2/go.mod h1:n7UGz/ckNChHiK05rDoiC4MYSunEC/lyaUm2WWaDva0=
-gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
-gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
@@ -544,44 +167,3 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o=
gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g=
-helm.sh/helm/v3 v3.18.4 h1:pNhnHM3nAmDrxz6/UC+hfjDY4yeDATQCka2/87hkZXQ=
-helm.sh/helm/v3 v3.18.4/go.mod h1:WVnwKARAw01iEdjpEkP7Ii1tT1pTPYfM1HsakFKM3LI=
-k8s.io/api v0.33.2 h1:YgwIS5jKfA+BZg//OQhkJNIfie/kmRsO0BmNaVSimvY=
-k8s.io/api v0.33.2/go.mod h1:fhrbphQJSM2cXzCWgqU29xLDuks4mu7ti9vveEnpSXs=
-k8s.io/apiextensions-apiserver v0.33.2 h1:6gnkIbngnaUflR3XwE1mCefN3YS8yTD631JXQhsU6M8=
-k8s.io/apiextensions-apiserver v0.33.2/go.mod h1:IvVanieYsEHJImTKXGP6XCOjTwv2LUMos0YWc9O+QP8=
-k8s.io/apimachinery v0.33.2 h1:IHFVhqg59mb8PJWTLi8m1mAoepkUNYmptHsV+Z1m5jY=
-k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
-k8s.io/apiserver v0.33.2 h1:KGTRbxn2wJagJowo29kKBp4TchpO1DRO3g+dB/KOJN4=
-k8s.io/apiserver v0.33.2/go.mod h1:9qday04wEAMLPWWo9AwqCZSiIn3OYSZacDyu/AcoM/M=
-k8s.io/cli-runtime v0.33.2 h1:koNYQKSDdq5AExa/RDudXMhhtFasEg48KLS2KSAU74Y=
-k8s.io/cli-runtime v0.33.2/go.mod h1:gnhsAWpovqf1Zj5YRRBBU7PFsRc6NkEkwYNQE+mXL88=
-k8s.io/client-go v0.33.2 h1:z8CIcc0P581x/J1ZYf4CNzRKxRvQAwoAolYPbtQes+E=
-k8s.io/client-go v0.33.2/go.mod h1:9mCgT4wROvL948w6f6ArJNb7yQd7QsvqavDeZHvNmHo=
-k8s.io/component-base v0.33.2 h1:sCCsn9s/dG3ZrQTX/Us0/Sx2R0G5kwa0wbZFYoVp/+0=
-k8s.io/component-base v0.33.2/go.mod h1:/41uw9wKzuelhN+u+/C59ixxf4tYQKW7p32ddkYNe2k=
-k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
-k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
-k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4=
-k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8=
-k8s.io/kubectl v0.33.2 h1:7XKZ6DYCklu5MZQzJe+CkCjoGZwD1wWl7t/FxzhMz7Y=
-k8s.io/kubectl v0.33.2/go.mod h1:8rC67FB8tVTYraovAGNi/idWIK90z2CHFNMmGJZJ3KI=
-k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979 h1:jgJW5IePPXLGB8e/1wvd0Ich9QE97RvvF3a8J3fP/Lg=
-k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
-oras.land/oras-go/v2 v2.6.0 h1:X4ELRsiGkrbeox69+9tzTu492FMUu7zJQW6eJU+I2oc=
-oras.land/oras-go/v2 v2.6.0/go.mod h1:magiQDfG6H1O9APp+rOsvCPcW1GD2MM7vgnKY0Y+u1o=
-sigs.k8s.io/controller-runtime v0.21.0 h1:CYfjpEuicjUecRk+KAeyYh+ouUBn4llGyDYytIGcJS8=
-sigs.k8s.io/controller-runtime v0.21.0/go.mod h1:OSg14+F65eWqIu4DceX7k/+QRAbTTvxeQSNSOQpukWM=
-sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=
-sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
-sigs.k8s.io/kustomize/api v0.19.0 h1:F+2HB2mU1MSiR9Hp1NEgoU2q9ItNOaBJl0I4Dlus5SQ=
-sigs.k8s.io/kustomize/api v0.19.0/go.mod h1:/BbwnivGVcBh1r+8m3tH1VNxJmHSk1PzP5fkP6lbL1o=
-sigs.k8s.io/kustomize/kyaml v0.19.0 h1:RFge5qsO1uHhwJsu3ipV7RNolC7Uozc0jUBC/61XSlA=
-sigs.k8s.io/kustomize/kyaml v0.19.0/go.mod h1:FeKD5jEOH+FbZPpqUghBP8mrLjJ3+zD3/rf9NNu1cwY=
-sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
-sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
-sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
-sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc=
-sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps=
-sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
-sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
From 7a765c4819988b23e7fdf892fc30184813f5937c Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 17 Feb 2026 13:59:16 +0100
Subject: [PATCH 10/19] Bump the minor-and-patches group across 1 directory
with 3 updates (#19469)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Bumps the minor-and-patches group with 3 updates in the / directory:
[docker/login-action](https://github.com/docker/login-action),
[actions/setup-python](https://github.com/actions/setup-python) and
[actions/cache](https://github.com/actions/cache).
Updates `docker/login-action` from 3.6.0 to 3.7.0
Release notes
Sourced from docker/login-action's
releases.
v3.7.0
Full Changelog: https://github.com/docker/login-action/compare/v3.6.0...v3.7.0
Commits
c94ce9f
Merge pull request #915
from docker/dependabot/npm_and_yarn/lodash-4.17.23
8339c95
Merge pull request #912
from docker/scope
c83e932
build(deps): bump lodash from 4.17.21 to 4.17.23
b268aa5
chore: update generated content
a603229
documentation for scope input
7567f92
Add scope input to set scopes for the authentication token
0567fa5
Merge pull request #914
from dphi/add-support-for-amazonaws.eu
f6ef577
feat: add support for AWS European Sovereign Cloud ECR registries
916386b
Merge pull request #911
from crazy-max/ensure-redact
5b3f94a
chore: update generated content
- Additional commits viewable in compare
view
Updates `actions/setup-python` from 6.1.0 to 6.2.0
Release notes
Sourced from actions/setup-python's
releases.
v6.2.0
What's Changed
Dependency Upgrades
Full Changelog: https://github.com/actions/setup-python/compare/v6...v6.2.0
Commits
Updates `actions/cache` from 5.0.1 to 5.0.3
Release notes
Sourced from actions/cache's
releases.
v5.0.3
What's Changed
Full Changelog: https://github.com/actions/cache/compare/v5...v5.0.3
v.5.0.2
v5.0.2
What's Changed
When creating cache entries, 429s returned from the cache service
will not be retried.
Changelog
Sourced from actions/cache's
changelog.
Releases
How to prepare a release
[!NOTE]
Relevant for maintainers with write access only.
- Switch to a new branch from
main.
- Run
npm test to ensure all tests are passing.
- Update the version in
https://github.com/actions/cache/blob/main/package.json.
- Run
npm run build to update the compiled files.
- Update this
https://github.com/actions/cache/blob/main/RELEASES.md
with the new version and changes in the ## Changelog
section.
- Run
licensed cache to update the license report.
- Run
licensed status and resolve any warnings by
updating the https://github.com/actions/cache/blob/main/.licensed.yml
file with the exceptions.
- Commit your changes and push your branch upstream.
- Open a pull request against
main and get it reviewed
and merged.
- Draft a new release https://github.com/actions/cache/releases
use the same version number used in
package.json
- Create a new tag with the version number.
- Auto generate release notes and update them to match the changes you
made in
RELEASES.md.
- Toggle the set as the latest release option.
- Publish the release.
- Navigate to https://github.com/actions/cache/actions/workflows/release-new-action-version.yml
- There should be a workflow run queued with the same version
number.
- Approve the run to publish the new version and update the major tags
for this action.
Changelog
5.0.3
5.0.2
- Bump
@actions/cache to v5.0.3 #1692
5.0.1
- Update
@azure/storage-blob to ^12.29.1 via
@actions/cache@5.0.1 #1685
5.0.0
[!IMPORTANT]
actions/cache@v5 runs on the Node.js 24 runtime and
requires a minimum Actions Runner version of 2.327.1.
If you are using self-hosted runners, ensure they are updated before
upgrading.
4.3.0
... (truncated)
Commits
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore ` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore ` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore ` will
remove the ignore condition of the specified dependency and ignore
conditions
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---
.github/workflows/docker.yml | 8 ++++----
.github/workflows/docs-pr.yaml | 2 +-
.github/workflows/docs.yaml | 2 +-
.github/workflows/latest_deps.yml | 2 +-
.github/workflows/poetry_lockfile.yaml | 2 +-
.github/workflows/push_complement_image.yml | 2 +-
.github/workflows/release-artifacts.yml | 10 +++++-----
.github/workflows/schema.yaml | 4 ++--
.github/workflows/tests.yml | 14 +++++++-------
9 files changed, 23 insertions(+), 23 deletions(-)
diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml
index bcd65b2f60..80504c569c 100644
--- a/.github/workflows/docker.yml
+++ b/.github/workflows/docker.yml
@@ -41,13 +41,13 @@ jobs:
echo "SYNAPSE_VERSION=$(grep "^version" pyproject.toml | sed -E 's/version\s*=\s*["]([^"]*)["]/\1/')" >> $GITHUB_ENV
- name: Log in to DockerHub
- uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
+ uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Log in to GHCR
- uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
+ uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
@@ -102,14 +102,14 @@ jobs:
merge-multiple: true
- name: Log in to DockerHub
- uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
+ uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
if: ${{ startsWith(matrix.repository, 'docker.io') }}
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Log in to GHCR
- uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
+ uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
if: ${{ startsWith(matrix.repository, 'ghcr.io') }}
with:
registry: ghcr.io
diff --git a/.github/workflows/docs-pr.yaml b/.github/workflows/docs-pr.yaml
index 424857822b..41f3664336 100644
--- a/.github/workflows/docs-pr.yaml
+++ b/.github/workflows/docs-pr.yaml
@@ -24,7 +24,7 @@ jobs:
mdbook-version: '0.5.2'
- name: Setup python
- uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
+ uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.x"
diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml
index 11fd8c6d6c..31f3b05b8e 100644
--- a/.github/workflows/docs.yaml
+++ b/.github/workflows/docs.yaml
@@ -64,7 +64,7 @@ jobs:
run: echo 'window.SYNAPSE_VERSION = "${{ needs.pre.outputs.branch-version }}";' > ./docs/website_files/version.js
- name: Setup python
- uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
+ uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.x"
diff --git a/.github/workflows/latest_deps.yml b/.github/workflows/latest_deps.yml
index dda4e5f57b..5bc78062cd 100644
--- a/.github/workflows/latest_deps.yml
+++ b/.github/workflows/latest_deps.yml
@@ -93,7 +93,7 @@ jobs:
-e POSTGRES_PASSWORD=postgres \
-e POSTGRES_INITDB_ARGS="--lc-collate C --lc-ctype C --encoding UTF8" \
postgres:${{ matrix.postgres-version }}
- - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
+ - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.x"
- run: pip install .[all,test]
diff --git a/.github/workflows/poetry_lockfile.yaml b/.github/workflows/poetry_lockfile.yaml
index fb4c449b58..5042a564f2 100644
--- a/.github/workflows/poetry_lockfile.yaml
+++ b/.github/workflows/poetry_lockfile.yaml
@@ -17,7 +17,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
+ - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: '3.x'
- run: pip install tomli
diff --git a/.github/workflows/push_complement_image.yml b/.github/workflows/push_complement_image.yml
index e6d0894e83..12b4720ca5 100644
--- a/.github/workflows/push_complement_image.yml
+++ b/.github/workflows/push_complement_image.yml
@@ -48,7 +48,7 @@ jobs:
with:
ref: master
- name: Login to registry
- uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
+ uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
with:
registry: ghcr.io
username: ${{ github.actor }}
diff --git a/.github/workflows/release-artifacts.yml b/.github/workflows/release-artifacts.yml
index 5f5b64dc64..4343cb482f 100644
--- a/.github/workflows/release-artifacts.yml
+++ b/.github/workflows/release-artifacts.yml
@@ -28,7 +28,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
+ - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.x"
- id: set-distros
@@ -64,7 +64,7 @@ jobs:
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
- name: Set up docker layer caching
- uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
+ uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
@@ -72,7 +72,7 @@ jobs:
${{ runner.os }}-buildx-
- name: Set up python
- uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
+ uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.x"
@@ -125,7 +125,7 @@ jobs:
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
+ - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
# setup-python@v4 doesn't impose a default python version. Need to use 3.x
# here, because `python` on osx points to Python 2.7.
@@ -162,7 +162,7 @@ jobs:
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
+ - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.10"
diff --git a/.github/workflows/schema.yaml b/.github/workflows/schema.yaml
index b068e976db..430ff8861a 100644
--- a/.github/workflows/schema.yaml
+++ b/.github/workflows/schema.yaml
@@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
+ - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.x"
- name: Install check-jsonschema
@@ -41,7 +41,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
+ - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.x"
- name: Install PyYAML
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index f575adb5c5..81a72f1f68 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -107,7 +107,7 @@ jobs:
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
+ - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.x"
- run: "pip install 'click==8.1.1' 'GitPython>=3.1.20' 'sqlglot>=28.0.0'"
@@ -117,7 +117,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
+ - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.x"
- run: .ci/scripts/check_lockfile.py
@@ -174,7 +174,7 @@ jobs:
# Cribbed from
# https://github.com/AustinScola/mypy-cache-github-action/blob/85ea4f2972abed39b33bd02c36e341b28ca59213/src/restore.ts#L10-L17
- name: Restore/persist mypy's cache
- uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
+ uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
with:
path: |
.mypy_cache
@@ -200,7 +200,7 @@ jobs:
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 0
- - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
+ - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.x"
- run: "pip install 'towncrier>=18.6.0rc1'"
@@ -308,7 +308,7 @@ jobs:
if: ${{ needs.changes.outputs.linting_readme == 'true' }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
+ - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.x"
- run: "pip install rstcheck"
@@ -355,7 +355,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
+ - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.x"
- id: get-matrix
@@ -446,7 +446,7 @@ jobs:
sudo apt-get -qq install build-essential libffi-dev python3-dev \
libxml2-dev libxslt-dev xmlsec1 zlib1g-dev libjpeg-dev libwebp-dev
- - uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
+ - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: "3.10"
From b0b4203cb6090b9c79e597d65eadebb5b3fbb843 Mon Sep 17 00:00:00 2001
From: Eric Eastwood
Date: Tue, 17 Feb 2026 07:04:17 -0600
Subject: [PATCH 11/19] Fix `/sync` missing membership in `state_after`
(#19463)
---
changelog.d/19463.bugfix | 1 +
synapse/handlers/sync.py | 15 ++++++++++++---
2 files changed, 13 insertions(+), 3 deletions(-)
create mode 100644 changelog.d/19463.bugfix
diff --git a/changelog.d/19463.bugfix b/changelog.d/19463.bugfix
new file mode 100644
index 0000000000..fe44c2ddf6
--- /dev/null
+++ b/changelog.d/19463.bugfix
@@ -0,0 +1 @@
+Fix `/sync` missing membership event in `state_after` (experimental [MSC4222](https://github.com/matrix-org/matrix-spec-proposals/pull/4222) implementation) in some scenarios.
diff --git a/synapse/handlers/sync.py b/synapse/handlers/sync.py
index 72e91d66ac..ab050adb26 100644
--- a/synapse/handlers/sync.py
+++ b/synapse/handlers/sync.py
@@ -1041,9 +1041,18 @@ async def compute_state_delta(
if event.sender not in first_event_by_sender_map:
first_event_by_sender_map[event.sender] = event
- # We need the event's sender, unless their membership was in a
- # previous timeline event.
- if (EventTypes.Member, event.sender) not in timeline_state:
+ # When using `state_after`, there is no special treatment with
+ # regards to state also being in the `timeline`. Always fetch
+ # relevant membership regardless of whether the state event is in
+ # the `timeline`.
+ if sync_config.use_state_after:
+ members_to_fetch.add(event.sender)
+ # For `state`, the client is supposed to do a flawed re-construction
+ # of state over time by starting with the given `state` and layering
+ # on state from the `timeline` as you go (flawed because state
+ # resolution). In this case, we only need their membership in
+ # `state` when their membership isn't already in the `timeline`.
+ elif (EventTypes.Member, event.sender) not in timeline_state:
members_to_fetch.add(event.sender)
# FIXME: we also care about invite targets etc.
From 69b931f30572a7fefdd2bd548550585245cad2b9 Mon Sep 17 00:00:00 2001
From: Devon Hudson
Date: Tue, 17 Feb 2026 13:35:38 +0000
Subject: [PATCH 12/19] Push Synapse docker images to Element OCI Registry
(#19420)
Part of https://github.com/element-hq/serverproduct-internal/issues/1153
Pushes Synapse docker images to the Element OCI Registry in addition to
the dockerhub and ghcr registries.
Ready for review despite Draft status. See
https://github.com/element-hq/synapse/pull/19420#issuecomment-3848866071
### Pull Request Checklist
* [X] Pull request is based on the develop branch
* [X] Pull request includes a [changelog
file](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#changelog).
The entry should:
- Be a short description of your change which makes sense to users.
"Fixed a bug that prevented receiving messages from other servers."
instead of "Moved X method from `EventStore` to `EventWorkerStore`.".
- Use markdown where necessary, mostly for `code blocks`.
- End with either a period (.) or an exclamation mark (!).
- Start with a capital letter.
- Feel free to credit yourself, by adding a sentence "Contributed by
@github_username." or "Contributed by [Your Name]." to the end of the
entry.
* [X] [Code
style](https://element-hq.github.io/synapse/latest/code_style.html) is
correct (run the
[linters](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#run-the-linters))
---------
Co-authored-by: Quentin Gliech
---
.github/workflows/docker.yml | 66 ++++++++++++++++++++++++++++++++++++
changelog.d/19420.misc | 1 +
2 files changed, 67 insertions(+)
create mode 100644 changelog.d/19420.misc
diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml
index 80504c569c..ca20e9652d 100644
--- a/.github/workflows/docker.yml
+++ b/.github/workflows/docker.yml
@@ -53,6 +53,38 @@ jobs:
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
+ - name: Tailscale
+ uses: tailscale/github-action@53acf823325fe9ca47f4cdaa951f90b4b0de5bb9 # v4.1.1
+ with:
+ oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }}
+ audience: ${{ secrets.TS_AUDIENCE }}
+ tags: tag:github-actions
+
+ - name: Compute vault jwt role name
+ id: vault-jwt-role
+ run: |
+ echo "role_name=github_service_management_$( echo "${{ github.repository }}" | sed -r 's|[/-]|_|g')" | tee -a "$GITHUB_OUTPUT"
+
+ - name: Get team registry token
+ id: import-secrets
+ uses: hashicorp/vault-action@4c06c5ccf5c0761b6029f56cfb1dcf5565918a3b # v3.4.0
+ with:
+ url: https://vault.infra.ci.i.element.dev
+ role: ${{ steps.vault-jwt-role.outputs.role_name }}
+ path: service-management/github-actions
+ jwtGithubAudience: https://vault.infra.ci.i.element.dev
+ method: jwt
+ secrets: |
+ services/backend-repositories/secret/data/oci.element.io username | OCI_USERNAME ;
+ services/backend-repositories/secret/data/oci.element.io password | OCI_PASSWORD ;
+
+ - name: Login to Element OCI Registry
+ uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
+ with:
+ registry: oci-push.vpn.infra.element.io
+ username: ${{ steps.import-secrets.outputs.OCI_USERNAME }}
+ password: ${{ steps.import-secrets.outputs.OCI_PASSWORD }}
+
- name: Build and push by digest
id: build
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
@@ -64,6 +96,7 @@ jobs:
tags: |
docker.io/matrixdotorg/synapse
ghcr.io/element-hq/synapse
+ oci-push.vpn.infra.element.io/synapse
file: "docker/Dockerfile"
platforms: ${{ matrix.platform }}
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
@@ -90,6 +123,7 @@ jobs:
repository:
- docker.io/matrixdotorg/synapse
- ghcr.io/element-hq/synapse
+ - oci-push.vpn.infra.element.io/synapse
needs:
- build
@@ -116,6 +150,38 @@ jobs:
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
+ - name: Tailscale
+ uses: tailscale/github-action@53acf823325fe9ca47f4cdaa951f90b4b0de5bb9 # v4.1.1
+ with:
+ oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }}
+ audience: ${{ secrets.TS_AUDIENCE }}
+ tags: tag:github-actions
+
+ - name: Compute vault jwt role name
+ id: vault-jwt-role
+ run: |
+ echo "role_name=github_service_management_$( echo "${{ github.repository }}" | sed -r 's|[/-]|_|g')" | tee -a "$GITHUB_OUTPUT"
+
+ - name: Get team registry token
+ id: import-secrets
+ uses: hashicorp/vault-action@4c06c5ccf5c0761b6029f56cfb1dcf5565918a3b # v3.4.0
+ with:
+ url: https://vault.infra.ci.i.element.dev
+ role: ${{ steps.vault-jwt-role.outputs.role_name }}
+ path: service-management/github-actions
+ jwtGithubAudience: https://vault.infra.ci.i.element.dev
+ method: jwt
+ secrets: |
+ services/backend-repositories/secret/data/oci.element.io username | OCI_USERNAME ;
+ services/backend-repositories/secret/data/oci.element.io password | OCI_PASSWORD ;
+
+ - name: Login to Element OCI Registry
+ uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
+ with:
+ registry: oci-push.vpn.infra.element.io
+ username: ${{ steps.import-secrets.outputs.OCI_USERNAME }}
+ password: ${{ steps.import-secrets.outputs.OCI_PASSWORD }}
+
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
diff --git a/changelog.d/19420.misc b/changelog.d/19420.misc
new file mode 100644
index 0000000000..7b3718ce1a
--- /dev/null
+++ b/changelog.d/19420.misc
@@ -0,0 +1 @@
+Push Synapse docker images to Element OCI Registry.
From 3669d6e3df77db699b60b12cf061db8f5b995f73 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 17 Feb 2026 14:43:41 +0100
Subject: [PATCH 13/19] Bump reqwest from 0.12.26 to 0.12.28 (#19444)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Bumps [reqwest](https://github.com/seanmonstar/reqwest) from 0.12.26 to
0.12.28.
Release notes
Sourced from reqwest's
releases.
v0.12.28
What's Changed
Full Changelog: https://github.com/seanmonstar/reqwest/compare/v0.12.27...v0.12.28
v0.12.27
tl;dr
- Add
ClientBuilder::windows_named_pipe(name) option that
will force all requests over that Windows Named Pipe.
What's Changed
Full Changelog: https://github.com/seanmonstar/reqwest/compare/v0.12.26...v0.12.27
Changelog
Sourced from reqwest's
changelog.
v0.12.28
- Fix compiling on Windows if TLS and SOCKS features are not
enabled.
v0.12.27
- Add
ClientBuilder::windows_named_pipe(name) option that
will force all requests over that Windows Named Piper.
Commits
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
Signed-off-by: dependabot[bot]
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Quentin Gliech
---
Cargo.lock | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index c981d139d4..47f81eaef1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1024,9 +1024,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]]
name = "reqwest"
-version = "0.12.26"
+version = "0.12.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b4c14b2d9afca6a60277086b0cc6a6ae0b568f6f7916c943a8cdc79f8be240f"
+checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147"
dependencies = [
"base64",
"bytes",
From e627b08786cb24c966e8f4f4da92b34035dde9fe Mon Sep 17 00:00:00 2001
From: Erik Johnston
Date: Tue, 17 Feb 2026 14:48:59 +0100
Subject: [PATCH 14/19] Add cargo.lock to Rust build hash (#19470)
This is so that when we update dependencies etc we correctly ensure that
the Rust library has been rebuilt.
---
changelog.d/19470.misc | 1 +
rust/build.rs | 14 ++++++++++++++
synapse/util/rust.py | 19 +++++++++++++------
3 files changed, 28 insertions(+), 6 deletions(-)
create mode 100644 changelog.d/19470.misc
diff --git a/changelog.d/19470.misc b/changelog.d/19470.misc
new file mode 100644
index 0000000000..e253d89b17
--- /dev/null
+++ b/changelog.d/19470.misc
@@ -0,0 +1 @@
+Correctly refuse to start if the Rust workspace config has changed and the Rust library has not been rebuilt.
diff --git a/rust/build.rs b/rust/build.rs
index ef370e6b41..8755f3bfa3 100644
--- a/rust/build.rs
+++ b/rust/build.rs
@@ -29,6 +29,13 @@ fn main() -> Result<(), std::io::Error> {
}
}
+ // Manually add Cargo.toml's, Cargo.lock and build.rs to the hash, since changes to
+ // these files should also invalidate the built module.
+ paths.push("Cargo.toml".to_string());
+ paths.push("../Cargo.lock".to_string());
+ paths.push("../Cargo.toml".to_string());
+ paths.push("build.rs".to_string());
+
paths.sort();
let mut hasher = Blake2b512::new();
@@ -41,5 +48,12 @@ fn main() -> Result<(), std::io::Error> {
let hex_digest = hex::encode(hasher.finalize());
println!("cargo:rustc-env=SYNAPSE_RUST_DIGEST={hex_digest}");
+ // The default rules don't pick up trivial changes to the workspace config
+ // files, but we need to rebuild if those change to pick up the changed
+ // hashes.
+ println!("cargo::rerun-if-changed=.");
+ println!("cargo::rerun-if-changed=../Cargo.lock");
+ println!("cargo::rerun-if-changed=../Cargo.toml");
+
Ok(())
}
diff --git a/synapse/util/rust.py b/synapse/util/rust.py
index d1e1a259e4..a7c9e976ea 100644
--- a/synapse/util/rust.py
+++ b/synapse/util/rust.py
@@ -40,24 +40,24 @@ def check_rust_lib_up_to_date() -> None:
return None
# Get the hash of all Rust source files
- rust_path = os.path.join(synapse_root, "rust", "src")
+ rust_path = os.path.join(synapse_root, "rust")
if not os.path.exists(rust_path):
return None
- hash = _hash_rust_files_in_directory(rust_path)
+ hash = _hash_rust_files_in_directory(synapse_root)
if hash != get_rust_file_digest():
raise Exception("Rust module outdated. Please rebuild using `poetry install`")
-def _hash_rust_files_in_directory(directory: str) -> str:
+def _hash_rust_files_in_directory(synapse_root: str) -> str:
"""Get the hash of all files in a directory (recursively)"""
- directory = os.path.abspath(directory)
+ src_directory = os.path.abspath(os.path.join(synapse_root, "rust", "src"))
paths = []
- dirs = [directory]
+ dirs = [src_directory]
while dirs:
dir = dirs.pop()
with os.scandir(dir) as d:
@@ -67,13 +67,20 @@ def _hash_rust_files_in_directory(directory: str) -> str:
else:
paths.append(entry.path)
+ # Manually add Cargo.toml's, Cargo.lock and build.rs to the hash, since
+ # changes to these files should also invalidate the built module.
+ paths.append(os.path.join(synapse_root, "rust", "Cargo.toml"))
+ paths.append(os.path.join(synapse_root, "rust", "build.rs"))
+ paths.append(os.path.join(synapse_root, "Cargo.lock"))
+ paths.append(os.path.join(synapse_root, "Cargo.toml"))
+
# We sort to make sure that we get a consistent and well-defined ordering.
paths.sort()
hasher = blake2b()
for path in paths:
- with open(os.path.join(directory, path), "rb") as f:
+ with open(path, "rb") as f:
hasher.update(f.read())
return hasher.hexdigest()
From bd0756c6ca6edd83149bfaf30a874d09bd9cbf0b Mon Sep 17 00:00:00 2001
From: Quentin Gliech
Date: Tue, 17 Feb 2026 17:41:14 +0100
Subject: [PATCH 15/19] Revert "Fix `/sync` missing membership in
`state_after`" (#19474)
Reverts element-hq/synapse#19463
The complement tests haven't been reviewed and require more testing.
Discussed in the internal [backend team
lobby](https://matrix.to/#/!SGNQGPGUwtcPBUotTL:matrix.org/$XDARK2u2iLL5wWaxiL6tJYkLg80Sn6yWWEQib8ahl5Q?via=jki.re&via=element.io&via=matrix.org)
room.
---
changelog.d/19463.bugfix | 1 -
synapse/handlers/sync.py | 15 +++------------
2 files changed, 3 insertions(+), 13 deletions(-)
delete mode 100644 changelog.d/19463.bugfix
diff --git a/changelog.d/19463.bugfix b/changelog.d/19463.bugfix
deleted file mode 100644
index fe44c2ddf6..0000000000
--- a/changelog.d/19463.bugfix
+++ /dev/null
@@ -1 +0,0 @@
-Fix `/sync` missing membership event in `state_after` (experimental [MSC4222](https://github.com/matrix-org/matrix-spec-proposals/pull/4222) implementation) in some scenarios.
diff --git a/synapse/handlers/sync.py b/synapse/handlers/sync.py
index ab050adb26..72e91d66ac 100644
--- a/synapse/handlers/sync.py
+++ b/synapse/handlers/sync.py
@@ -1041,18 +1041,9 @@ async def compute_state_delta(
if event.sender not in first_event_by_sender_map:
first_event_by_sender_map[event.sender] = event
- # When using `state_after`, there is no special treatment with
- # regards to state also being in the `timeline`. Always fetch
- # relevant membership regardless of whether the state event is in
- # the `timeline`.
- if sync_config.use_state_after:
- members_to_fetch.add(event.sender)
- # For `state`, the client is supposed to do a flawed re-construction
- # of state over time by starting with the given `state` and layering
- # on state from the `timeline` as you go (flawed because state
- # resolution). In this case, we only need their membership in
- # `state` when their membership isn't already in the `timeline`.
- elif (EventTypes.Member, event.sender) not in timeline_state:
+ # We need the event's sender, unless their membership was in a
+ # previous timeline event.
+ if (EventTypes.Member, event.sender) not in timeline_state:
members_to_fetch.add(event.sender)
# FIXME: we also care about invite targets etc.
From 40171d036acec6f0315bbac77bd7f073bd64feb9 Mon Sep 17 00:00:00 2001
From: Quentin Gliech
Date: Tue, 17 Feb 2026 17:44:37 +0100
Subject: [PATCH 16/19] 1.148.0rc1
---
CHANGES.md | 24 ++++++++++++++++++++++++
changelog.d/19365.feature | 1 -
changelog.d/19406.misc | 1 -
changelog.d/19420.misc | 1 -
changelog.d/19429.removal | 1 -
changelog.d/19435.doc | 1 -
changelog.d/19457.misc | 1 -
changelog.d/19470.misc | 1 -
debian/changelog | 6 ++++++
pyproject.toml | 2 +-
schema/synapse-config.schema.yaml | 2 +-
11 files changed, 32 insertions(+), 9 deletions(-)
delete mode 100644 changelog.d/19365.feature
delete mode 100644 changelog.d/19406.misc
delete mode 100644 changelog.d/19420.misc
delete mode 100644 changelog.d/19429.removal
delete mode 100644 changelog.d/19435.doc
delete mode 100644 changelog.d/19457.misc
delete mode 100644 changelog.d/19470.misc
diff --git a/CHANGES.md b/CHANGES.md
index fe27ccb040..e4bec3aa41 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,3 +1,27 @@
+# Synapse 1.148.0rc1 (2026-02-17)
+
+## Features
+
+- Support sending and receiving [MSC4354 Sticky Event](https://github.com/matrix-org/matrix-spec-proposals/pull/4354) metadata. ([\#19365](https://github.com/element-hq/synapse/issues/19365))
+
+## Improved Documentation
+
+- Fix reference to the `experimental_features` section of config. ([\#19435](https://github.com/element-hq/synapse/issues/19435))
+
+## Deprecations and Removals
+
+- Remove support for [MSC3244: Room version capabilities](https://github.com/matrix-org/matrix-spec-proposals/pull/3244) as the MSC was rejected. ([\#19429](https://github.com/element-hq/synapse/issues/19429))
+
+## Internal Changes
+
+- Add in-repo Complement tests so we can test Synapse specific behavior at an end-to-end level. ([\#19406](https://github.com/element-hq/synapse/issues/19406))
+- Push Synapse docker images to Element OCI Registry. ([\#19420](https://github.com/element-hq/synapse/issues/19420))
+- Allow configuring the Rust HTTP client to use HTTP/2 only. ([\#19457](https://github.com/element-hq/synapse/issues/19457))
+- Correctly refuse to start if the Rust workspace config has changed and the Rust library has not been rebuilt. ([\#19470](https://github.com/element-hq/synapse/issues/19470))
+
+
+
+
# Synapse 1.147.1 (2026-02-12)
## Internal Changes
diff --git a/changelog.d/19365.feature b/changelog.d/19365.feature
deleted file mode 100644
index c35afdc179..0000000000
--- a/changelog.d/19365.feature
+++ /dev/null
@@ -1 +0,0 @@
-Support sending and receiving [MSC4354 Sticky Event](https://github.com/matrix-org/matrix-spec-proposals/pull/4354) metadata.
\ No newline at end of file
diff --git a/changelog.d/19406.misc b/changelog.d/19406.misc
deleted file mode 100644
index bfe8d6afb0..0000000000
--- a/changelog.d/19406.misc
+++ /dev/null
@@ -1 +0,0 @@
-Add in-repo Complement tests so we can test Synapse specific behavior at an end-to-end level.
diff --git a/changelog.d/19420.misc b/changelog.d/19420.misc
deleted file mode 100644
index 7b3718ce1a..0000000000
--- a/changelog.d/19420.misc
+++ /dev/null
@@ -1 +0,0 @@
-Push Synapse docker images to Element OCI Registry.
diff --git a/changelog.d/19429.removal b/changelog.d/19429.removal
deleted file mode 100644
index b52ca2423d..0000000000
--- a/changelog.d/19429.removal
+++ /dev/null
@@ -1 +0,0 @@
-Remove support for [MSC3244: Room version capabilities](https://github.com/matrix-org/matrix-spec-proposals/pull/3244) as the MSC was rejected.
\ No newline at end of file
diff --git a/changelog.d/19435.doc b/changelog.d/19435.doc
deleted file mode 100644
index 4edf2f73dc..0000000000
--- a/changelog.d/19435.doc
+++ /dev/null
@@ -1 +0,0 @@
-Fix reference to the `experimental_features` section of config.
diff --git a/changelog.d/19457.misc b/changelog.d/19457.misc
deleted file mode 100644
index ccbb7f5b14..0000000000
--- a/changelog.d/19457.misc
+++ /dev/null
@@ -1 +0,0 @@
-Allow configuring the Rust HTTP client to use HTTP/2 only.
diff --git a/changelog.d/19470.misc b/changelog.d/19470.misc
deleted file mode 100644
index e253d89b17..0000000000
--- a/changelog.d/19470.misc
+++ /dev/null
@@ -1 +0,0 @@
-Correctly refuse to start if the Rust workspace config has changed and the Rust library has not been rebuilt.
diff --git a/debian/changelog b/debian/changelog
index a6852dac5e..105ea2fcec 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+matrix-synapse-py3 (1.148.0~rc1) stable; urgency=medium
+
+ * New synapse release 1.148.0rc1.
+
+ -- Synapse Packaging team Tue, 17 Feb 2026 16:44:08 +0000
+
matrix-synapse-py3 (1.147.1) stable; urgency=medium
* New synapse release 1.147.1.
diff --git a/pyproject.toml b/pyproject.toml
index 8073f8ec44..07455c57df 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "matrix-synapse"
-version = "1.147.1"
+version = "1.148.0rc1"
description = "Homeserver for the Matrix decentralised comms protocol"
readme = "README.rst"
authors = [
diff --git a/schema/synapse-config.schema.yaml b/schema/synapse-config.schema.yaml
index 99c9b6e9bd..42e9ed87dd 100644
--- a/schema/synapse-config.schema.yaml
+++ b/schema/synapse-config.schema.yaml
@@ -1,5 +1,5 @@
$schema: https://element-hq.github.io/synapse/latest/schema/v1/meta.schema.json
-$id: https://element-hq.github.io/synapse/schema/synapse/v1.147/synapse-config.schema.json
+$id: https://element-hq.github.io/synapse/schema/synapse/v1.148/synapse-config.schema.json
type: object
properties:
modules:
From 32c5f01bcb6e7070bfb014569e9979de3df26959 Mon Sep 17 00:00:00 2001
From: Quentin Gliech
Date: Tue, 17 Feb 2026 18:33:08 +0100
Subject: [PATCH 17/19] Minor reword
---
CHANGES.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CHANGES.md b/CHANGES.md
index e4bec3aa41..e52ca3ed30 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -6,7 +6,7 @@
## Improved Documentation
-- Fix reference to the `experimental_features` section of config. ([\#19435](https://github.com/element-hq/synapse/issues/19435))
+- Fix reference to the `experimental_features` section of the configuration manual documentation. ([\#19435](https://github.com/element-hq/synapse/issues/19435))
## Deprecations and Removals
From e3fc6dc96586edfdc97df46ad6ef1489d71014df Mon Sep 17 00:00:00 2001
From: FrenchGithubUser
Date: Thu, 26 Feb 2026 16:23:14 +0100
Subject: [PATCH 18/19] Update changelog
---
CHANGES.md | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/CHANGES.md b/CHANGES.md
index e3c36f1a53..ea5c737e6b 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,3 +1,11 @@
+# Synapse 1.148.0 (2026-02-24)
+
+### Famedly additions for v1.148.0_1
+- chore: fix the inconsistent stream error log message to contain the proper information instead of rasing value error ([\#238](https://github.com/famedly/synapse/pull/238)) (itsoyou & FrenchGithubUser)
+
+
+
+
# Synapse 1.148.0rc1 (2026-02-17)
## Features
From f14f80146b39702d2a1bffca49ca92a79ce085e7 Mon Sep 17 00:00:00 2001
From: FrenchGithubUser
Date: Thu, 26 Feb 2026 16:38:34 +0100
Subject: [PATCH 19/19] chore: run lint script
---
synapse/events/__init__.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/synapse/events/__init__.py b/synapse/events/__init__.py
index 7f07fc089c..35b0506f66 100644
--- a/synapse/events/__init__.py
+++ b/synapse/events/__init__.py
@@ -329,6 +329,7 @@ def unfreeze(self) -> None:
# this will be a no-op if the event dict is not frozen.
self._dict = unfreeze(self._dict)
+
def sticky_duration(self) -> Duration | None:
"""
Returns the effective sticky duration of this event, or None