diff --git a/gso/__init__.py b/gso/__init__.py
index 94c8f5fa273a584cf542da257c0289952567857d..ecdfd940ffefe85df1613e4a6cbbc74f56bf80dc 100644
--- a/gso/__init__.py
+++ b/gso/__init__.py
@@ -28,7 +28,7 @@ def init_worker_app() -> OrchestratorCore:
 
 def init_cli_app() -> typer.Typer:
     """Initialise :term:`GSO` as a CLI application."""
-    from gso.cli import imports, netbox
+    from gso.cli import imports, netbox  # noqa: PLC0415
 
     cli_app.add_typer(imports.app, name="import-cli")
     cli_app.add_typer(netbox.app, name="netbox-cli")
diff --git a/gso/schedules/scheduling.py b/gso/schedules/scheduling.py
index 2e83fab3613526c9cd3571def4ad1dff101c1443..b0e22a0916cb730c1058f661688111dd49d26737 100644
--- a/gso/schedules/scheduling.py
+++ b/gso/schedules/scheduling.py
@@ -7,16 +7,21 @@ from typing import Any
 
 from celery import current_app
 from celery.schedules import crontab
+from pydantic import BaseModel
 
 
-def scheduler(
-    name: str,
-    minute: str = "*",
-    hour: str = "*",
-    day_of_week: str = "*",
-    day_of_month: str = "*",
-    month_of_year: str = "*",
-) -> Callable[[Callable], Callable]:
+class CronScheduleConfig(BaseModel):
+    """Configuration for scheduling a task using crontab-like timing parameters."""
+
+    name: str
+    minute: str = "*"
+    hour: str = "*"
+    day_of_week: str = "*"
+    day_of_month: str = "*"
+    month_of_year: str = "*"
+
+
+def scheduler(cron_scheduler_config: CronScheduleConfig) -> Callable[[Callable], Callable]:
     """Schedule a Celery task using crontab-like timing.
 
     Examples
@@ -44,14 +49,14 @@ def scheduler(
 
         task_path = f"{module.__name__}.{task_func.__name__}"
         current_app.conf.beat_schedule[task_func.__name__] = {
-            "name": name,
+            "name": cron_scheduler_config.name,
             "task": task_path,
             "schedule": crontab(
-                minute=minute,
-                hour=hour,
-                day_of_month=day_of_month,
-                month_of_year=month_of_year,
-                day_of_week=day_of_week,
+                minute=cron_scheduler_config.minute,
+                hour=cron_scheduler_config.hour,
+                day_of_month=cron_scheduler_config.day_of_month,
+                month_of_year=cron_scheduler_config.month_of_year,
+                day_of_week=cron_scheduler_config.day_of_week,
             ),
         }
 
diff --git a/gso/schedules/task_vacuum.py b/gso/schedules/task_vacuum.py
index 98e05343dff0c701dd6e48f229d1e553e4149358..be04380f8caaf53152f77ca129ba74b9d63bd164 100644
--- a/gso/schedules/task_vacuum.py
+++ b/gso/schedules/task_vacuum.py
@@ -2,12 +2,12 @@
 
 from orchestrator.services.processes import start_process
 
-from gso.schedules.scheduling import scheduler
+from gso.schedules.scheduling import CronScheduleConfig, scheduler
 from gso.worker import celery
 
 
 @celery.task
-@scheduler(name="Clean up tasks", hour="*/6")
+@scheduler(CronScheduleConfig(name="Clean up tasks", hour="*/6"))
 def vacuum_tasks() -> None:
     """Run all cleanup tasks every 6 hours."""
     start_process("task_clean_up_tasks")
diff --git a/gso/schedules/validate_products.py b/gso/schedules/validate_products.py
index cb9ecc675264835dd4f13dc0069be61f3472f742..580c7540db85e3565fd62c6a183f880490e9f593 100644
--- a/gso/schedules/validate_products.py
+++ b/gso/schedules/validate_products.py
@@ -2,13 +2,13 @@
 
 from orchestrator.services.processes import start_process
 
-from gso.schedules.scheduling import scheduler
+from gso.schedules.scheduling import CronScheduleConfig, scheduler
 from gso.services.subscriptions import count_incomplete_validate_products
 from gso.worker import celery
 
 
 @celery.task
-@scheduler(name="Validate Products and inactive subscriptions", minute="30", hour="2")
+@scheduler(CronScheduleConfig(name="Validate Products and inactive subscriptions", minute="30", hour="2"))
 def validate_products() -> None:
     """Validate all products."""
     if count_incomplete_validate_products() > 0:
diff --git a/gso/schedules/validate_subscriptions.py b/gso/schedules/validate_subscriptions.py
index 7c4404356a656291c169cb665ac1a12e56ce0e38..9e79ec91cabda776762147bd0b86226fe8256879 100644
--- a/gso/schedules/validate_subscriptions.py
+++ b/gso/schedules/validate_subscriptions.py
@@ -5,7 +5,7 @@ from orchestrator.services.processes import get_execution_context
 from orchestrator.services.subscriptions import TARGET_DEFAULT_USABLE_MAP, WF_USABLE_MAP
 from orchestrator.targets import Target
 
-from gso.schedules.scheduling import scheduler
+from gso.schedules.scheduling import CronScheduleConfig, scheduler
 from gso.services.subscriptions import get_insync_subscriptions
 from gso.worker import celery
 
@@ -13,7 +13,7 @@ logger = structlog.get_logger(__name__)
 
 
 @celery.task
-@scheduler(name="Subscriptions Validator", minute="10", hour="0")
+@scheduler(CronScheduleConfig(name="Subscriptions Validator", minute="10", hour="0"))
 def validate_subscriptions() -> None:
     """Validate all subscriptions using their corresponding validation workflow."""
     subscriptions = get_insync_subscriptions()
diff --git a/gso/services/infoblox.py b/gso/services/infoblox.py
index 514c55cbc571d7127429f53fa9eedbc12e4cf9af..874ee6f5c219d9f2b7e984ba8eb78fee69feca1f 100644
--- a/gso/services/infoblox.py
+++ b/gso/services/infoblox.py
@@ -37,7 +37,7 @@ def _setup_connection() -> tuple[connector.Connector, IPAMParams]:
     return connector.Connector(options), oss
 
 
-def _allocate_network(
+def _allocate_network(  # noqa: PLR0917
     conn: connector.Connector,
     dns_view: str,
     network_view: str,
diff --git a/gso/utils/shared_enums.py b/gso/utils/shared_enums.py
index 1054876fb8823a002c278455e0fa450c2da31ae6..6a5905157f8592c89087f4d19382eeeddd2dde21 100644
--- a/gso/utils/shared_enums.py
+++ b/gso/utils/shared_enums.py
@@ -1,13 +1,18 @@
 """Shared choices for the different models."""
 
 import ipaddress
-from typing import Annotated
+from typing import Annotated, Any
 
 from pydantic import Field, PlainSerializer
 from pydantic_forms.types import strEnum
 from typing_extensions import Doc
 
 
+def convert_to_str(value: Any) -> str:
+    """Convert the value to a string."""
+    return str(value)
+
+
 class Vendor(strEnum):
     """Enumerator for the different product vendors that are supported."""
 
@@ -29,11 +34,11 @@ PortNumber = Annotated[
 
 
 IPv4AddressType = Annotated[
-    ipaddress.IPv4Address, PlainSerializer(lambda ip: str(ip), return_type=str, when_used="always")
+    ipaddress.IPv4Address, PlainSerializer(convert_to_str, return_type=str, when_used="always")
 ]
 
 IPv6AddressType = Annotated[
-    ipaddress.IPv6Address, PlainSerializer(lambda ip: str(ip), return_type=str, when_used="always")
+    ipaddress.IPv6Address, PlainSerializer(convert_to_str, return_type=str, when_used="always")
 ]
 
 
diff --git a/gso/worker.py b/gso/worker.py
index b1a3db2c95935e960b699563745f327edc829987..b2abfe6f5a52192454d3d691ba1715df313fc6ac 100644
--- a/gso/worker.py
+++ b/gso/worker.py
@@ -9,7 +9,7 @@ from gso.settings import load_oss_params
 class OrchestratorCelery(Celery):
     """A :term:`GSO` instance that functions as a Celery worker."""
 
-    def on_init(self) -> None:
+    def on_init(self) -> None:  # noqa: PLR6301
         """Initialise a new Celery worker."""
         init_worker_app()
 
diff --git a/pyproject.toml b/pyproject.toml
index 34c2cc108340206038184e37e9c47d99e2ef0023..376371b7d41c286cd416a176fc760ce25cd1a663 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -113,3 +113,6 @@ filterwarnings = [
     "ignore",
     "default:::gso",
 ]
+[tool.ruff.lint.per-file-ignores]
+"test/*" = ["PLR0917", "S101", "D104", "D105", "D103", "D100", "ARG001", "D102", "PLR2004", "D101", "D106", "D107", "PLR0914", "PLC0415", "PLC2701"]
+"gso/workflows/*" = ["PLR0917", "PLR0914"]
\ No newline at end of file
diff --git a/setup.py b/setup.py
index 08fa01b80709230ebc0707717025a2bdbcfaec9e..6339e95aebecdd751059d9fe88bd83a02f7afdd0 100644
--- a/setup.py
+++ b/setup.py
@@ -1,3 +1,5 @@
+"""Setup script for the GÉANT Service Orchestrator."""
+
 from setuptools import find_packages, setup
 
 setup(
diff --git a/test/auth/test_oidc_policy_helper.py b/test/auth/test_oidc_policy_helper.py
index 767e34423a5c4969d3a08fc4d5ee01f005fc0b40..46b934caad20f93ea55e1f66cd7fa3b9d6694d20 100644
--- a/test/auth/test_oidc_policy_helper.py
+++ b/test/auth/test_oidc_policy_helper.py
@@ -268,7 +268,7 @@ async def test_oidc_user_call_no_token(oidc_user, mock_request):
         mock_post.return_value = MagicMock(status_code=200, json=lambda: {"active": False})
         mock_get.return_value = MagicMock(status_code=200, json=dict)
 
-        result = await oidc_user.__call__(mock_request)
+        result = await oidc_user.__call__(mock_request)  # noqa: PLC2801
 
     assert result is None
 
@@ -281,7 +281,7 @@ async def test_oidc_user_call_token_from_request(oidc_user, mock_request, mock_a
     oidc_user.introspect_token = AsyncMock(return_value={"active": True})
     oidc_user.userinfo = AsyncMock(return_value=OIDCUserModel({"sub": "123", "name": "John Doe"}))
 
-    result = await oidc_user.__call__(mock_request)
+    result = await oidc_user.__call__(mock_request)  # noqa: PLC2801
 
     assert isinstance(result, OIDCUserModel)
     assert result["sub"] == "123"
diff --git a/test/conftest.py b/test/conftest.py
index a5d4279839d452801453e7d2368e8b2513bf6c81..8fae41e74198cd47d0cc6543b60b3b459b6be273 100644
--- a/test/conftest.py
+++ b/test/conftest.py
@@ -57,7 +57,7 @@ def pytest_collection_modifyitems(config, items):
 
 
 class UseJuniperSide(strEnum):
-    """Define on tests on which side to use Juniper router"""
+    """Define on tests on which side to use Juniper router."""
 
     NONE = "none"
     SIDE_A = "side_a"
diff --git a/test/schedules/test_scheduling.py b/test/schedules/test_scheduling.py
index 82168eb4375f2bdb50ed2c4de34fe9e0f65cd8cb..17811174369913a4f47f532a8c6bbd115717a946 100644
--- a/test/schedules/test_scheduling.py
+++ b/test/schedules/test_scheduling.py
@@ -3,7 +3,7 @@ from unittest.mock import MagicMock, patch
 import pytest
 from orchestrator.targets import Target
 
-from gso.schedules.scheduling import scheduler
+from gso.schedules.scheduling import CronScheduleConfig, scheduler
 
 
 @pytest.fixture(scope="module")
@@ -42,12 +42,14 @@ def test_scheduler_updates_beat_schedule(mock_celery):
     mock_celery.conf.beat_schedule = {}
 
     @scheduler(
-        name="A cool task",
-        minute="0",
-        hour="0",
-        day_of_week="*",
-        day_of_month="*",
-        month_of_year="*",
+        CronScheduleConfig(
+            name="A cool task",
+            minute="0",
+            hour="0",
+            day_of_week="*",
+            day_of_month="*",
+            month_of_year="*",
+        )
     )
     def mock_task():
         return "task result"
@@ -64,12 +66,14 @@ def test_scheduled_task_still_works():
     """Ensure that the scheduler decorator does not change the behavior of the function it decorates."""
 
     @scheduler(
-        name="A cool task",
-        minute="0",
-        hour="0",
-        day_of_week="*",
-        day_of_month="*",
-        month_of_year="*",
+        CronScheduleConfig(
+            name="A cool task",
+            minute="0",
+            hour="0",
+            day_of_week="*",
+            day_of_month="*",
+            month_of_year="*",
+        )
     )
     def mock_task():
         return "task result"
diff --git a/test/utils/test_helpers.py b/test/utils/test_helpers.py
index 5dee0aa8f7a5cb981771a63cdfec933986423991..e80e6f30049635fdcc4691c9c75f8e13dfbbfb67 100644
--- a/test/utils/test_helpers.py
+++ b/test/utils/test_helpers.py
@@ -23,7 +23,7 @@ def mock_netbox_client():
 
 @pytest.fixture()
 def generate_tt_numbers(faker, request):
-    """Generator for valid and invalid tt numbers."""
+    """Get a Generator for valid and invalid tt numbers."""
     valid_count = request.param.get("valid", 0)
     invalid_count = request.param.get("invalid", 0)
 
@@ -78,7 +78,7 @@ def test_nokia_router_with_interfaces_returns_choice(mock_router, mock_netbox_cl
 
 @pytest.mark.parametrize("generate_tt_numbers", [{"valid": 5, "invalid": 3}], indirect=True)
 def test_tt_number(generate_tt_numbers):
-    """Test different TT numbers"""
+    """Test different TT numbers."""
     for tt_number, is_valid in generate_tt_numbers:
         if is_valid:
             assert validate_tt_number(tt_number) == tt_number
diff --git a/test/workflows/__init__.py b/test/workflows/__init__.py
index 246d2b767b253699ce6b56cea36aeaa9ca156fea..b44bace935639aa7eac5716750a3204243e4bd21 100644
--- a/test/workflows/__init__.py
+++ b/test/workflows/__init__.py
@@ -157,7 +157,8 @@ class WorkflowInstanceForTests(LazyWorkflowInstance):
         This can be as simple as merely importing a workflow function. However, if it concerns a workflow generating
         function, that function will be called with or without arguments as specified.
 
-        Returns:
+        Returns
+        -------
             A workflow function.
 
         """