Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions synapse/config/homeserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
from .sso import SSOConfig
from .stats import StatsConfig
from .third_party_event_rules import ThirdPartyRulesConfig
from .tim import TimConfig
from .tls import TlsConfig
from .tracer import TracerConfig
from .user_directory import UserDirectoryConfig
Expand Down Expand Up @@ -117,6 +118,7 @@ class HomeServerConfig(RootConfig):
BackgroundUpdateConfig,
AutoAcceptInvitesConfig,
UserTypesConfig,
TimConfig,
# This must be last, as it checks for conflicts with other config options.
MasConfig,
]
Expand Down
38 changes: 38 additions & 0 deletions synapse/config/tim.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#
# This file is licensed under the Affero General Public License (AGPL) version 3.
#
# Copyright (C) 2026 Famedly GmbH
#
# 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:
# <https://www.gnu.org/licenses/agpl-3.0.html>.
#

from typing import Any

from synapse.config._base import Config, ConfigError
from synapse.types import JsonDict

VALID_TIM_VERSIONS = ("1.1", "1.2")


class TimConfig(Config):
"""Config section for TIM-specific settings."""

section = "tim"

def read_config(self, config: JsonDict, **kwargs: Any) -> None:
tim_version = config.get("tim_version", "1.1")

if tim_version not in VALID_TIM_VERSIONS:
raise ConfigError(
f"tim_version must be one of {', '.join(VALID_TIM_VERSIONS)}, "
f"got {tim_version!r}",
("tim_version",),
)
Comment on lines +28 to +36
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tim_version values in YAML may be parsed as numbers if unquoted (e.g. tim_version: 1.2). Currently those will always be rejected because you're comparing against string literals. Consider coercing tim_version to str (similar to how default_room_version is handled) before validation, or at least raise a clearer error telling users to quote the value.

Copilot uses AI. Check for mistakes.

self.tim_version: str = tim_version
57 changes: 57 additions & 0 deletions tests/config/test_tim.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#
# This file is licensed under the Affero General Public License (AGPL) version 3.
#
# Copyright (C) 2026 Famedly GmbH
#
# 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:
# <https://www.gnu.org/licenses/agpl-3.0.html>.
#

from synapse.config import ConfigError
from synapse.config.homeserver import HomeServerConfig

from tests.unittest import TestCase
from tests.utils import default_config


class TimConfigTestCase(TestCase):
def _parse_config(self, extra: dict) -> HomeServerConfig:
config_dict = {**default_config("test"), **extra}
config = HomeServerConfig()
config.parse_config_dict(config_dict, "", "")
return config

def test_default_tim_version(self) -> None:
"""tim_version defaults to '1.1' when not set."""
config = self._parse_config({})
self.assertEqual(config.tim.tim_version, "1.1")

Comment on lines +29 to +33
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test doesn't currently exercise the "not set" default: default_config() now always includes tim_version (from TIM_VERSION_FOR_TESTS), so _parse_config({}) is still explicitly setting it. Consider removing/popping tim_version from the base config dict for this test so it actually verifies the TimConfig default and doesn't fail when SYNAPSE_TIM_VERSION is set for the test run.

Copilot uses AI. Check for mistakes.
def test_tim_version_1_1(self) -> None:
"""tim_version can be explicitly set to '1.1'."""
config = self._parse_config({"tim_version": "1.1"})
self.assertEqual(config.tim.tim_version, "1.1")

def test_tim_version_1_2(self) -> None:
"""tim_version can be set to '1.2'."""
config = self._parse_config({"tim_version": "1.2"})
self.assertEqual(config.tim.tim_version, "1.2")

def test_invalid_tim_version_rejected(self) -> None:
"""An invalid tim_version should raise ConfigError."""
with self.assertRaises(ConfigError):
self._parse_config({"tim_version": "2.0"})

def test_invalid_tim_version_string(self) -> None:
"""A non-version string should raise ConfigError."""
with self.assertRaises(ConfigError):
self._parse_config({"tim_version": "invalid"})

def test_invalid_tim_version_numeric(self) -> None:
"""A numeric (non-string) tim_version should raise ConfigError."""
with self.assertRaises(ConfigError):
self._parse_config({"tim_version": 1.1})
Comment on lines +54 to +57
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If tim_version is intended to be configured via YAML, users may naturally write tim_version: 1.1 / 1.2 (unquoted), which YAML parses as a number. Right now the test enforces that numeric values error, but that would make common config files fail. Consider either accepting numeric values by coercing to str, or updating the error message + tests to explicitly require quoting.

Suggested change
def test_invalid_tim_version_numeric(self) -> None:
"""A numeric (non-string) tim_version should raise ConfigError."""
with self.assertRaises(ConfigError):
self._parse_config({"tim_version": 1.1})
def test_tim_version_numeric_coerced(self) -> None:
"""A numeric tim_version is accepted by coercing it to a string."""
config = self._parse_config({"tim_version": 1.1})
self.assertEqual(config.tim.tim_version, "1.1")

Copilot uses AI. Check for mistakes.
4 changes: 4 additions & 0 deletions tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@
# DB to disk and query it with the sqlite CLI.
SQLITE_PERSIST_DB = os.environ.get("SYNAPSE_TEST_PERSIST_SQLITE_DB") is not None

# Defaults to 1.1
TIM_VERSION_FOR_TESTS = os.environ.get("SYNAPSE_TIM_VERSION", "1.1")

# the dbname we will connect to in order to create the base database.
POSTGRES_DBNAME_FOR_INITIAL_CREATE = "postgres"

Expand Down Expand Up @@ -219,6 +222,7 @@ def default_config(
"update_user_directory_from_worker": "does_not_exist_worker_name",
"caches": {"global_factor": 1, "sync_response_cache_duration": 0},
"listeners": [{"port": 0, "type": "http"}],
"tim_version": TIM_VERSION_FOR_TESTS,
}

if parse:
Expand Down
Loading