diff --git a/.github/workflows/run-e2e-tests.yml b/.github/workflows/run-e2e-tests.yml index e1d7db417b..0411ef602f 100644 --- a/.github/workflows/run-e2e-tests.yml +++ b/.github/workflows/run-e2e-tests.yml @@ -31,6 +31,7 @@ jobs: REDIS: ${{ inputs.redis_enabled }} REDIS_HOST: keep-redis REDIS_PORT: 6379 + REDIS_DB: 0 BACKEND_IMAGE: ${{ inputs.backend-image-name }} FRONTEND_IMAGE: ${{ inputs.frontend-image-name }} steps: diff --git a/.github/workflows/test-docs.yml b/.github/workflows/test-docs.yml index 61aad64d57..bf7af046ea 100644 --- a/.github/workflows/test-docs.yml +++ b/.github/workflows/test-docs.yml @@ -28,6 +28,7 @@ jobs: - uses: chartboost/ruff-action@v1 with: src: "./keep" + version: 0.11.4 - name: Set up Python ${{ env.PYTHON_VERSION }} uses: actions/setup-python@v4 with: diff --git a/.github/workflows/test-pr-ut.yml b/.github/workflows/test-pr-ut.yml index 3ebad25949..fee80985ed 100644 --- a/.github/workflows/test-pr-ut.yml +++ b/.github/workflows/test-pr-ut.yml @@ -34,6 +34,7 @@ jobs: - uses: chartboost/ruff-action@v1 with: src: "./keep" + version: 0.11.4 - name: Set up Python ${{ env.PYTHON_VERSION }} uses: actions/setup-python@v4 diff --git a/.github/workflows/test-workflow-examples.yml b/.github/workflows/test-workflow-examples.yml index c8754a8188..65049c56cc 100644 --- a/.github/workflows/test-workflow-examples.yml +++ b/.github/workflows/test-workflow-examples.yml @@ -32,6 +32,7 @@ jobs: - uses: chartboost/ruff-action@v1 with: src: "./keep" + version: 0.11.4 - name: Set up Python ${{ env.PYTHON_VERSION }} uses: actions/setup-python@v4 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2fc9e4e62c..2593ac58c4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -28,7 +28,7 @@ repos: stages: [commit, push, manual] - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.1.6 + rev: v0.11.4 hooks: # Run the linter. - id: ruff diff --git a/docker-compose-with-arq.yml b/docker-compose-with-arq.yml index 9c2f0f300d..e9172a940f 100644 --- a/docker-compose-with-arq.yml +++ b/docker-compose-with-arq.yml @@ -22,6 +22,7 @@ services: - REDIS=true - REDIS_HOST=keep-arq-redis - REDIS_PORT=6379 + - REDIS_DB=0 volumes: - ./state:/state depends_on: diff --git a/docs/deployment/configuration.mdx b/docs/deployment/configuration.mdx index e70738df53..ee403877c3 100644 --- a/docs/deployment/configuration.mdx +++ b/docs/deployment/configuration.mdx @@ -280,6 +280,7 @@ The authenticated entity will have: | **REDIS** | Redis enabled | No | false | true or false | | **REDIS_HOST** | Redis server hostname | No | "localhost" | Valid hostname or IP address | | **REDIS_PORT** | Redis server port | No | 6379 | Valid port number | +| **REDIS_DB** | Redis database slot | No | 0 | Valid DB number | | **REDIS_USERNAME** | Redis username | No | None | Valid username string | | **REDIS_PASSWORD** | Redis password | No | None | Valid password string | @@ -294,6 +295,7 @@ The authenticated entity will have: | **REDIS** | Redis enabled | No | false | true or false | | **REDIS_SENTINEL_HOSTS** | Redis sentinel server(s) | No | "localhost:26379" | "host1:port1,host2:port2" (comma-separated) | | **REDIS_SENTINEL_SERVICE_NAME** | Redis sentinel service name | No | "mymaster" | Valid service name string | +| **REDIS_DB** | Redis database slot | No | 0 | Valid DB number | | **REDIS_USERNAME** | Redis username | No | None | Valid username string | | **REDIS_PASSWORD** | Redis password | No | None | Valid password string | diff --git a/keep/api/redis_settings.py b/keep/api/redis_settings.py index c68b65a2cb..55e30dbb8e 100644 --- a/keep/api/redis_settings.py +++ b/keep/api/redis_settings.py @@ -6,6 +6,7 @@ """ from arq.connections import RedisSettings + from keep.api.core.config import config @@ -22,6 +23,7 @@ def get_redis_settings() -> RedisSettings: For direct Redis (default): - REDIS_HOST=localhost (default: localhost) - REDIS_PORT=6379 (default: 6379) + - REDIS_DB=0 (default: 0) Returns: RedisSettings: Configured Redis settings for ARQ @@ -49,6 +51,7 @@ def get_redis_settings() -> RedisSettings: sentinel_master=service_name, username=config("REDIS_USERNAME", default=None), password=config("REDIS_PASSWORD", default=None), + database=config("REDIS_DB", cast=int, default=0), ssl=ssl_enabled, conn_timeout=60, conn_retries=10, @@ -60,6 +63,7 @@ def get_redis_settings() -> RedisSettings: port=config("REDIS_PORT", cast=int, default=6379), username=config("REDIS_USERNAME", default=None), password=config("REDIS_PASSWORD", default=None), + database=config("REDIS_DB", cast=int, default=0), ssl=ssl_enabled, conn_timeout=60, conn_retries=10, diff --git a/pyproject.toml b/pyproject.toml index 86853c8ba4..9dfb05575d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -126,6 +126,9 @@ build-backend = "poetry.core.masonry.api" [tool.poetry.scripts] keep = "keep.cli.cli:cli" +[tool.ruff] +required-version = "0.11.4" + [tool.ruff.lint] ignore = ["F405", "F811", "E712", "E711", "F403"] diff --git a/tests/e2e_tests/docker-compose-e2e-mysql.yml b/tests/e2e_tests/docker-compose-e2e-mysql.yml index af081159c0..2c3e0fa324 100644 --- a/tests/e2e_tests/docker-compose-e2e-mysql.yml +++ b/tests/e2e_tests/docker-compose-e2e-mysql.yml @@ -42,6 +42,7 @@ services: - SQLALCHEMY_WARN_20=1 - REDIS=${REDIS:-false} - REDIS_HOST=${REDIS_HOST:-localhost} + - REDIS_DB=${REDIS_DB:-0} ports: - "8080:8080" depends_on: diff --git a/tests/e2e_tests/docker-compose-e2e-postgres.yml b/tests/e2e_tests/docker-compose-e2e-postgres.yml index 72c9e0bf56..9ccef35b36 100644 --- a/tests/e2e_tests/docker-compose-e2e-postgres.yml +++ b/tests/e2e_tests/docker-compose-e2e-postgres.yml @@ -42,6 +42,7 @@ services: - SQLALCHEMY_WARN_20=1 - REDIS=${REDIS:-false} - REDIS_HOST=${REDIS_HOST:-localhost} + - REDIS_DB=${REDIS_DB:-0} depends_on: - keep-database diff --git a/tests/e2e_tests/docker-compose-e2e-redis.yml b/tests/e2e_tests/docker-compose-e2e-redis.yml index 20f1a3ea58..b78efd9a18 100644 --- a/tests/e2e_tests/docker-compose-e2e-redis.yml +++ b/tests/e2e_tests/docker-compose-e2e-redis.yml @@ -27,6 +27,7 @@ services: - REDIS=true - REDIS_HOST=keep-arq-redis - REDIS_PORT=6379 + - REDIS_DB=0 depends_on: - keep-redis diff --git a/tests/e2e_tests/docker-compose-e2e-sqlite.yml b/tests/e2e_tests/docker-compose-e2e-sqlite.yml index 928b52e822..93494cf8dd 100644 --- a/tests/e2e_tests/docker-compose-e2e-sqlite.yml +++ b/tests/e2e_tests/docker-compose-e2e-sqlite.yml @@ -24,6 +24,7 @@ services: - SQLALCHEMY_WARN_20=1 - REDIS=${REDIS:-false} - REDIS_HOST=${REDIS_HOST:-localhost} + - REDIS_DB=${REDIS_DB:-0} ports: - "8080:8080" diff --git a/tests/e2e_tests/test_end_to_end.py b/tests/e2e_tests/test_end_to_end.py index 320cc16101..f182fbab3c 100644 --- a/tests/e2e_tests/test_end_to_end.py +++ b/tests/e2e_tests/test_end_to_end.py @@ -827,7 +827,7 @@ def test_run_workflow_from_alert_and_incident( select = modal.get_by_test_id("manual-run-workflow-select-control") choose_combobox_option_with_retry(page, select, "Log every incident") modal.get_by_role("button", name="Run").click() - expect(page.get_by_text("Workflow started successfully")).to_be_visible() + expect(page.get_by_text("Workflow started successfully").first).to_be_visible() # Run workflow from alert page.locator("[data-testid='menu-alerts-feed-link']").click() # wait for the alerts facets to load, so it doesn't interfere with the dropdown @@ -843,7 +843,7 @@ def test_run_workflow_from_alert_and_incident( select = modal.get_by_test_id("manual-run-workflow-select-control") choose_combobox_option_with_retry(page, select, "Log every alert") modal.get_by_role("button", name="Run").click() - expect(page.get_by_text("Workflow started successfully")).to_be_visible() + expect(page.get_by_text("Workflow started successfully").first).to_be_visible() except Exception: save_failure_artifacts(page, log_entries) raise diff --git a/tests/test_redis_settings.py b/tests/test_redis_settings.py new file mode 100644 index 0000000000..690749fd18 --- /dev/null +++ b/tests/test_redis_settings.py @@ -0,0 +1,58 @@ +import os +from unittest.mock import patch + +from keep.api.redis_settings import get_redis_settings + + +class TestGetRedisSettings: + def test_default_redis_db(self): + with patch.dict(os.environ, {}, clear=True): + settings = get_redis_settings() + assert settings.database == 0 + + def test_custom_redis_db(self): + with patch.dict(os.environ, {"REDIS_DB": "7"}, clear=True): + settings = get_redis_settings() + assert settings.database == 7 + + def test_redis_db_with_sentinel(self): + with patch.dict( + os.environ, + { + "REDIS_SENTINEL_ENABLED": "true", + "REDIS_SENTINEL_HOSTS": "localhost:26379", + "REDIS_SENTINEL_SERVICE_NAME": "mymaster", + "REDIS_DB": "3", + }, + clear=True, + ): + settings = get_redis_settings() + assert settings.database == 3 + assert settings.sentinel is True + + def test_redis_db_defaults_to_zero_with_sentinel(self): + with patch.dict( + os.environ, + { + "REDIS_SENTINEL_ENABLED": "true", + "REDIS_SENTINEL_HOSTS": "localhost:26379", + "REDIS_SENTINEL_SERVICE_NAME": "mymaster", + }, + clear=True, + ): + settings = get_redis_settings() + assert settings.database == 0 + assert settings.sentinel is True + + def test_redis_db_with_ssl(self): + with patch.dict( + os.environ, + { + "REDIS_SSL": "true", + "REDIS_DB": "5", + }, + clear=True, + ): + settings = get_redis_settings() + assert settings.database == 5 + assert settings.ssl is True