feat: add MariaDB integration for database RCA#492
feat: add MariaDB integration for database RCA#492VaibhavUpreti merged 13 commits intoTracer-Cloud:mainfrom
Conversation
7457af0 to
1321822
Compare
There was a problem hiding this comment.
Pull request overview
Adds a first-class MariaDB integration to OpenSRE so investigations can query MariaDB safely (status, process list, InnoDB status, slow queries, replication), including wiring into integration resolution/verification and tool registration.
Changes:
- Introduces
app/integrations/mariadb.pywith normalized config, connectivity validation, and read-only diagnostic queries. - Adds 5 MariaDB investigation tools (function-based
@tool) and wires MariaDB into integration resolution, env loading, source detection, and verification. - Adds MariaDB-focused unit/contract tests, plus dependency and env template updates.
Reviewed changes
Copilot reviewed 22 out of 22 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
app/integrations/mariadb.py |
Core MariaDB config/validation + read-only query helpers for the 5 tools. |
app/tools/MariaDBStatusTool/__init__.py |
Tool wrapper for curated SHOW GLOBAL STATUS metrics. |
app/tools/MariaDBProcessListTool/__init__.py |
Tool wrapper for active process list queries. |
app/tools/MariaDBInnoDBStatusTool/__init__.py |
Tool wrapper for SHOW ENGINE INNODB STATUS. |
app/tools/MariaDBSlowQueriesTool/__init__.py |
Tool wrapper for performance_schema slow query summary. |
app/tools/MariaDBReplicationTool/__init__.py |
Tool wrapper for replication status queries. |
app/nodes/resolve_integrations/node.py |
Classifies/loads MariaDB credentials from store/env into resolved integrations. |
app/nodes/plan_actions/detect_sources.py |
Adds MariaDB to detected sources for investigations. |
app/integrations/verify.py |
Adds MariaDB to effective integrations and verification flow. |
app/integrations/models.py |
Adds MariaDB integration config model and effective-integrations entry. |
app/integrations/cli.py |
Adds interactive opensre integrations setup mariadb handler. |
app/cli/constants.py |
Adds mariadb to supported integration service lists. |
app/types/evidence.py |
Adds mariadb to the canonical EvidenceSource union. |
pyproject.toml |
Adds pymysql runtime dep and types-PyMySQL dev typing dep. |
.env.example |
Documents MariaDB env vars (MARIADB_*). |
tests/test_mariadb_integration.py |
Unit tests for config/env loading/validation and integration classification. |
tests/tools/conftest.py |
Adds MariaDB entry to mock agent state for tool contract tests. |
tests/tools/test_mariadb_status_tool.py |
Contract + basic behavior test for global status tool. |
tests/tools/test_mariadb_process_list_tool.py |
Contract + basic behavior test for process list tool. |
tests/tools/test_mariadb_innodb_status_tool.py |
Contract + basic behavior test for InnoDB status tool. |
tests/tools/test_mariadb_slow_queries_tool.py |
Contract + basic behavior test for slow queries tool. |
tests/tools/test_mariadb_replication_tool.py |
Contract + basic behavior test for replication tool. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| return pymysql.connect( | ||
| host=config.host, | ||
| port=config.port, | ||
| database=config.database, | ||
| user=config.username, | ||
| password=config.password, | ||
| ssl=ssl_arg, | ||
| connect_timeout=DEFAULT_MARIADB_TIMEOUT_S, | ||
| read_timeout=int(config.timeout_seconds), | ||
| write_timeout=int(config.timeout_seconds), | ||
| charset="utf8mb4", | ||
| autocommit=True, | ||
| program_name="opensre", | ||
| ) |
There was a problem hiding this comment.
_get_connection hard-codes connect_timeout=DEFAULT_MARIADB_TIMEOUT_S (5s) while the config’s timeout_seconds default is 10s and is used for read/write timeouts. This makes connect behavior inconsistent with the configured timeout and with the PR’s “timeouts enforced” claim. Consider deriving connect_timeout from config.timeout_seconds (or exposing a separate connect_timeout_seconds field) so all timeouts are consistently configurable.
| ssl_arg: dict[str, Any] | None = None | ||
| if config.ssl: | ||
| ssl_arg = {"check_hostname": False} | ||
|
|
||
| return pymysql.connect( | ||
| host=config.host, | ||
| port=config.port, | ||
| database=config.database, | ||
| user=config.username, | ||
| password=config.password, | ||
| ssl=ssl_arg, |
There was a problem hiding this comment.
When config.ssl is true, the SSL options explicitly disable hostname verification (check_hostname: False). That weakens TLS protections and can allow MITM if certificates are otherwise accepted. Prefer leaving hostname verification enabled by default and only disabling it via an explicit opt-out setting (or require a CA bundle / verify mode configuration).
| def validate_mariadb_config(config: MariaDBConfig) -> MariaDBValidationResult: | ||
| """Validate MariaDB connectivity with a lightweight version query.""" | ||
| if not config.host: | ||
| return MariaDBValidationResult(ok=False, detail="MariaDB host is required.") | ||
|
|
||
| try: | ||
| conn = _get_connection(config) | ||
| try: | ||
| with conn.cursor() as cur: | ||
| cur.execute("SELECT VERSION()") | ||
| row = cur.fetchone() | ||
| version = row[0] if row else "unknown" | ||
| db_name = config.database or "(default)" | ||
| return MariaDBValidationResult( | ||
| ok=True, | ||
| detail=f"Connected to MariaDB {version}; target database: {db_name}.", | ||
| ) |
There was a problem hiding this comment.
validate_mariadb_config only checks that host is set, but the rest of the integration (tools’ is_available and MariaDBConfig.is_configured) requires both host and database. This can lead to opensre integrations verify mariadb reporting success even when the DB name is missing and the tools won’t be available. Align validation with tool requirements by also requiring database (and likely username) to be non-empty for a “passed” result.
| with conn.cursor() as cur: | ||
| row = None | ||
| columns: list[str] = [] | ||
| # MariaDB-specific multi-source syntax first, then legacy | ||
| for stmt in ("SHOW ALL SLAVES STATUS", "SHOW SLAVE STATUS"): | ||
| try: | ||
| cur.execute(stmt) | ||
| row = cur.fetchone() | ||
| if cur.description: | ||
| columns = [d[0] for d in cur.description] | ||
| break | ||
| except Exception: # noqa: BLE001 | ||
| continue | ||
|
|
||
| if not row: | ||
| return { | ||
| "source": "mariadb", | ||
| "available": True, | ||
| "note": "This server is not configured as a replica.", | ||
| "replication": {}, | ||
| } | ||
|
|
||
| # Build a dict from column names and row values | ||
| full = dict(zip(columns, row)) | ||
| # Return curated subset (MariaDB uses Master/Slave naming) | ||
| _KEYS = ( | ||
| "Slave_IO_Running", | ||
| "Slave_SQL_Running", | ||
| "Seconds_Behind_Master", | ||
| "Last_Error", "Last_Errno", | ||
| "Master_Host", "Master_Port", | ||
| "Master_Log_File", | ||
| "Relay_Log_Space", | ||
| "Exec_Master_Log_Pos", | ||
| "Connection_name", | ||
| ) | ||
| replication = {k: full[k] for k in _KEYS if k in full} | ||
| return { | ||
| "source": "mariadb", | ||
| "available": True, | ||
| "replication": replication, | ||
| } |
There was a problem hiding this comment.
get_replication_status executes SHOW ALL SLAVES STATUS but only reads a single row via fetchone(). On multi-source replication setups this will silently drop additional channels, contradicting the stated multi-source support. Consider fetching all rows and returning a list of channel statuses (keyed by Connection_name) or aggregating them into a structured result.
| mariadb_int = (resolved_integrations or {}).get("mariadb") | ||
| if mariadb_int and str(mariadb_int.get("host", "")).strip(): | ||
| sources["mariadb"] = { | ||
| "host": str(mariadb_int.get("host", "")).strip(), | ||
| "port": mariadb_int.get("port", 3306), | ||
| "database": str(mariadb_int.get("database", "")).strip(), | ||
| "username": str(mariadb_int.get("username", "")).strip(), | ||
| "password": str(mariadb_int.get("password", "")).strip(), | ||
| "ssl": mariadb_int.get("ssl", True), | ||
| "connection_verified": True, | ||
| } |
There was a problem hiding this comment.
detect_sources adds a mariadb source when only host is present, but the MariaDB tools’ availability/config checks require both host and database. This can yield a partially-populated sources['mariadb'] with connection_verified=True while the tools still won’t show/run. Consider requiring a non-empty database here (or aligning mariadb_is_available/MariaDBConfig.is_configured to only require host if that’s intended).
| else: | ||
| mariadb_host = os.getenv("MARIADB_HOST", "").strip() | ||
| if mariadb_host: | ||
| effective["mariadb"] = { | ||
| "source": "local env", | ||
| "config": { | ||
| "host": mariadb_host, | ||
| "port": int(os.getenv("MARIADB_PORT", "3306").strip() or "3306"), | ||
| "database": os.getenv("MARIADB_DATABASE", "").strip(), | ||
| "username": os.getenv("MARIADB_USERNAME", "").strip(), | ||
| "password": os.getenv("MARIADB_PASSWORD", "").strip(), | ||
| "ssl": os.getenv("MARIADB_SSL", "true").strip().lower() in ("true", "1", "yes"), | ||
| }, | ||
| } |
There was a problem hiding this comment.
In the env-var fallback branch, resolve_effective_integrations treats MARIADB_HOST alone as sufficient to include MariaDB in the effective integrations, but the rest of the integration requires a non-empty database (and typically username). This can make verify/display flows report MariaDB as configured even when the tools will be unavailable. Consider only adding the env-backed MariaDB entry when the required fields are present, or make verification fail with a clear message when they’re missing.
| """Shared MariaDB integration helpers. | ||
|
|
||
| Provides configuration, connectivity validation, and read-only diagnostic | ||
| queries for MariaDB instances. All operations are production-safe: read-only, | ||
| timeouts enforced, result sizes capped. | ||
| """ |
There was a problem hiding this comment.
The repo has integration-level E2E coverage for other database integrations (e.g., tests/e2e/mongodb/test_mongodb_e2e.py covers resolution + verify + detect_sources + tools availability), but this PR only adds unit/contract tests for MariaDB. Consider adding a similar tests/e2e/mariadb/ suite to validate the full wiring (env/store resolution → verify → detect_sources → tool availability) and prevent regressions in the end-to-end investigation flow.
Greptile SummaryThis PR adds a MariaDB integration with 5 read-only diagnostic tools (process list, global status, InnoDB status, slow queries, replication), full CLI/wizard/verify wiring, and 57 new tests. Most of the serious issues flagged in prior rounds (missing Confidence Score: 4/5Safe to merge after addressing the dead-code model and confirming the slow-query timer units are correct in the live file. All prior critical issues (SyntaxError, TypeError, arity bug, missing _parse_port) appear resolved. Two P2 findings remain: MariaDBIntegrationConfig is dead code that adds confusion, and the new ssl.create_default_context() approach silently enforces strict cert+hostname verification. The slow-query timing values in get_slow_queries warrant a final sanity-check before merge. app/integrations/mariadb.py (slow-query timer divisor), app/integrations/models.py (unused MariaDBIntegrationConfig) Important Files Changed
|
| row = None | ||
| columns: list[str] = [] | ||
| # MariaDB-specific multi-source syntax first, then legacy | ||
| for stmt in ("SHOW ALL SLAVES STATUS", "SHOW SLAVE STATUS"): | ||
| try: | ||
| cur.execute(stmt) | ||
| row = cur.fetchone() | ||
| if cur.description: | ||
| columns = [d[0] for d in cur.description] | ||
| break | ||
| except Exception: # noqa: BLE001 | ||
| continue | ||
|
|
There was a problem hiding this comment.
Multi-source replication silently returns only the first replica
SHOW ALL SLAVES STATUS returns one row per master connection in a multi-source setup, but fetchone() discards every row after the first. The PR description explicitly claims multi-source support, so this is a present functional defect — any replica beyond the first is silently dropped.
| row = None | |
| columns: list[str] = [] | |
| # MariaDB-specific multi-source syntax first, then legacy | |
| for stmt in ("SHOW ALL SLAVES STATUS", "SHOW SLAVE STATUS"): | |
| try: | |
| cur.execute(stmt) | |
| row = cur.fetchone() | |
| if cur.description: | |
| columns = [d[0] for d in cur.description] | |
| break | |
| except Exception: # noqa: BLE001 | |
| continue | |
| rows = cur.fetchall() or [] | |
| if cur.description: | |
| columns = [d[0] for d in cur.description] | |
| break |
After this change, iterate rows to build a list of replica dicts, return "replicas": [...] instead of "replication": {}.
Prompt To Fix With AI
This is a comment left during a code review.
Path: app/integrations/mariadb.py
Line: 366-378
Comment:
**Multi-source replication silently returns only the first replica**
`SHOW ALL SLAVES STATUS` returns one row per master connection in a multi-source setup, but `fetchone()` discards every row after the first. The PR description explicitly claims multi-source support, so this is a present functional defect — any replica beyond the first is silently dropped.
```suggestion
rows = cur.fetchall() or []
if cur.description:
columns = [d[0] for d in cur.description]
break
```
After this change, iterate `rows` to build a list of replica dicts, return `"replicas": [...]` instead of `"replication": {}`.
How can I resolve this? If you propose a fix, please make it concise.|
|
||
| ssl_arg: dict[str, Any] | None = None | ||
| if config.ssl: | ||
| ssl_arg = {"check_hostname": False} |
There was a problem hiding this comment.
check_hostname is not a recognized pymysql SSL dict key
pymysql's ssl parameter accepts ca, cert, key, capath, and cipher. The key check_hostname is silently ignored, so hostname-verification behavior is undefined. Passing an empty dict {} or None is clearer and achieves the same "connect with TLS, no cert verification" effect that appears to be the intent here.
| ssl_arg: dict[str, Any] | None = None | |
| if config.ssl: | |
| ssl_arg = {"check_hostname": False} | |
| ssl_arg: dict[str, Any] | None = {} if config.ssl else None |
Prompt To Fix With AI
This is a comment left during a code review.
Path: app/integrations/mariadb.py
Line: 96-99
Comment:
**`check_hostname` is not a recognized pymysql SSL dict key**
pymysql's `ssl` parameter accepts `ca`, `cert`, `key`, `capath`, and `cipher`. The key `check_hostname` is silently ignored, so hostname-verification behavior is undefined. Passing an empty dict `{}` or `None` is clearer and achieves the same "connect with TLS, no cert verification" effect that appears to be the intent here.
```suggestion
ssl_arg: dict[str, Any] | None = {} if config.ssl else None
```
How can I resolve this? If you propose a fix, please make it concise.| try: | ||
| mariadb_config = build_mariadb_config({ | ||
| "host": credentials.get("host", ""), | ||
| "port": credentials.get("port", 3306), | ||
| "database": credentials.get("database", ""), | ||
| "username": credentials.get("username", ""), | ||
| "password": credentials.get("password", ""), | ||
| "ssl": credentials.get("ssl", True), | ||
| }) | ||
| except Exception: | ||
| continue | ||
|
|
||
| if mariadb_config.host and mariadb_config.database: | ||
| resolved["mariadb"] = mariadb_config.model_dump() |
There was a problem hiding this comment.
integration_id not propagated for MariaDB
Every other integration in _classify_integrations (Grafana, Datadog, Honeycomb, Coralogix, Sentry, Vercel, OpsGenie) passes "integration_id": integration.get("id", "") when building its config object. The MariaDB block omits this, so resolved["mariadb"]["integration_id"] is always "" for store-backed configurations.
| try: | |
| mariadb_config = build_mariadb_config({ | |
| "host": credentials.get("host", ""), | |
| "port": credentials.get("port", 3306), | |
| "database": credentials.get("database", ""), | |
| "username": credentials.get("username", ""), | |
| "password": credentials.get("password", ""), | |
| "ssl": credentials.get("ssl", True), | |
| }) | |
| except Exception: | |
| continue | |
| if mariadb_config.host and mariadb_config.database: | |
| resolved["mariadb"] = mariadb_config.model_dump() | |
| try: | |
| mariadb_config = build_mariadb_config({ | |
| "host": credentials.get("host", ""), | |
| "port": credentials.get("port", 3306), | |
| "database": credentials.get("database", ""), | |
| "username": credentials.get("username", ""), | |
| "password": credentials.get("password", ""), | |
| "ssl": credentials.get("ssl", True), | |
| "integration_id": integration.get("id", ""), | |
| }) |
Prompt To Fix With AI
This is a comment left during a code review.
Path: app/nodes/resolve_integrations/node.py
Line: 229-242
Comment:
**`integration_id` not propagated for MariaDB**
Every other integration in `_classify_integrations` (Grafana, Datadog, Honeycomb, Coralogix, Sentry, Vercel, OpsGenie) passes `"integration_id": integration.get("id", "")` when building its config object. The MariaDB block omits this, so `resolved["mariadb"]["integration_id"]` is always `""` for store-backed configurations.
```suggestion
try:
mariadb_config = build_mariadb_config({
"host": credentials.get("host", ""),
"port": credentials.get("port", 3306),
"database": credentials.get("database", ""),
"username": credentials.get("username", ""),
"password": credentials.get("password", ""),
"ssl": credentials.get("ssl", True),
"integration_id": integration.get("id", ""),
})
```
How can I resolve this? If you propose a fix, please make it concise.| WHERE SCHEMA_NAME = %s | ||
| OR SCHEMA_NAME IS NULL | ||
| ORDER BY AVG_TIMER_WAIT DESC | ||
| LIMIT %s |
There was a problem hiding this comment.
OR SCHEMA_NAME IS NULL may surface unrelated system queries
Rows with SCHEMA_NAME IS NULL in events_statements_summary_by_digest represent cross-schema or administrative statements (SHOW STATUS, SET NAMES, SELECT @@version, etc.) that are unrelated to the target application database. If these statements have a high AVG_TIMER_WAIT they can displace genuinely slow application queries in the results.
Consider removing the OR SCHEMA_NAME IS NULL clause unless including system-level statements is intentional:
| WHERE SCHEMA_NAME = %s | |
| OR SCHEMA_NAME IS NULL | |
| ORDER BY AVG_TIMER_WAIT DESC | |
| LIMIT %s | |
| WHERE SCHEMA_NAME = %s |
Prompt To Fix With AI
This is a comment left during a code review.
Path: app/integrations/mariadb.py
Line: 323-326
Comment:
**`OR SCHEMA_NAME IS NULL` may surface unrelated system queries**
Rows with `SCHEMA_NAME IS NULL` in `events_statements_summary_by_digest` represent cross-schema or administrative statements (`SHOW STATUS`, `SET NAMES`, `SELECT @@version`, etc.) that are unrelated to the target application database. If these statements have a high `AVG_TIMER_WAIT` they can displace genuinely slow application queries in the results.
Consider removing the `OR SCHEMA_NAME IS NULL` clause unless including system-level statements is intentional:
```suggestion
WHERE SCHEMA_NAME = %s
```
How can I resolve this? If you propose a fix, please make it concise.
@shanduur Tested MariaDB locally using Docker and verified the local env setup successfully. |
81915ab to
2ce6464
Compare
|
|
||
| import pytest | ||
|
|
||
| from app.integrations.cli import _parse_port |
There was a problem hiding this comment.
_parse_port does not exist — entire test file fails with ImportError
app.integrations.cli has no _parse_port function. Every test in TestParsePort will raise ImportError at collection time. The PR description claims "all MariaDB tests pass (57 new tests)", but this file cannot even be imported.
The actual port handling in _setup_mariadb uses int(port) if port.isdigit() else 3306, which also doesn't match the tests: "0".isdigit() and "65536".isdigit() both return True, so out-of-range ports are stored rather than falling back to the default.
_parse_port needs to be defined in app/integrations/cli.py and wired into _setup_mariadb:
def _parse_port(value: str, default: int = 3306) -> int:
try:
port = int(value)
except (ValueError, TypeError):
return default
return port if 1 <= port <= 65535 else defaultPrompt To Fix With AI
This is a comment left during a code review.
Path: tests/cli/test_mariadb_cli.py
Line: 7
Comment:
**`_parse_port` does not exist — entire test file fails with `ImportError`**
`app.integrations.cli` has no `_parse_port` function. Every test in `TestParsePort` will raise `ImportError` at collection time. The PR description claims "all MariaDB tests pass (57 new tests)", but this file cannot even be imported.
The actual port handling in `_setup_mariadb` uses `int(port) if port.isdigit() else 3306`, which also doesn't match the tests: `"0".isdigit()` and `"65536".isdigit()` both return `True`, so out-of-range ports are stored rather than falling back to the default.
`_parse_port` needs to be defined in `app/integrations/cli.py` and wired into `_setup_mariadb`:
```python
def _parse_port(value: str, default: int = 3306) -> int:
try:
port = int(value)
except (ValueError, TypeError):
return default
return port if 1 <= port <= 65535 else default
```
How can I resolve this? If you propose a fix, please make it concise.2ce6464 to
7607f03
Compare
| import pymysql | ||
|
|
||
| ssl_arg: dict[str, Any] | None = None | ||
| if config.ssl: |
There was a problem hiding this comment.
Passing an empty dict to ssl= in pymysql encrypts the channel but skips certificate verification. An attacker on the network can MITM the connection. For a tool that transmits database credentials, this is a meaningful risk.
Fix: pass {"ssl_verify_cert": True, "ssl_ca": "/etc/ssl/certs/ca-certificates.crt"}, or at minimum expose a ssl_verify_cert config option and document the default behavior.
There was a problem hiding this comment.
Good point, you're right that an empty dict skips verification. Changed it to pass ssl_verify_cert: True so pymysql actually validates the server certificate against system CAs.
| def _save(data: dict[str, Any]) -> None: | ||
| STORE_PATH.parent.mkdir(parents=True, exist_ok=True) | ||
| STORE_PATH.write_text(json.dumps(data, indent=2) + "\n") | ||
| STORE_PATH.chmod(0o600) |
There was a problem hiding this comment.
Correct for new files. However, a store file created by an older version (e.g. 0o644) stays world-readable until the next write. Consider adding a read-time check: if the file exists and its mode is not 0o600, fix it immediately before returning data.
| if cur.description: | ||
| columns = [d[0] for d in cur.description] | ||
| break | ||
| except Exception: # noqa: BLE001 |
There was a problem hiding this comment.
A bare except Exception here will silently swallow timeouts and connection-lost errors on SHOW ALL SLAVES STATUS and attempt SHOW SLAVE STATUS on a dead cursor. Should catch only the syntax/unsupported error:
except pymysql.err.ProgrammingError:
| cur.execute( | ||
| """ | ||
| SELECT DIGEST_TEXT, COUNT_STAR, | ||
| ROUND(AVG_TIMER_WAIT / 1000000000000, 4) AS avg_time_ms, |
There was a problem hiding this comment.
performance_schema timers count in picoseconds (10⁻¹²). Dividing by 10¹² gives seconds, not milliseconds. The column name avg_time_ms is wrong by 1000×.
Fix: divide by 1000000000 (10⁹) for ms, or rename the columns to avg_time_s.
eg
ROUND(AVG_TIMER_WAIT / 1000000000, 4) AS avg_time_ms,
ROUND(SUM_TIMER_WAIT / 1000000000, 4) AS total_time_ms,
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
| "source": "local env", | ||
| "config": { | ||
| "host": mariadb_host, | ||
| "port": int(os.getenv("MARIADB_PORT", "3306").strip() or "3306"), |
There was a problem hiding this comment.
Bare
int() crashes on invalid MARIADB_PORT
If MARIADB_HOST is set and MARIADB_PORT contains a non-numeric value (e.g. "localhost:3306", "abc"), int(...) raises ValueError with no surrounding try/except, crashing resolve_effective_integrations() entirely — breaking verification for all integrations, not just MariaDB. The parallel path in node.py's _load_env_integrations avoids this by routing through build_mariadb_config, which handles coercion gracefully via _normalize_port.
Reuse the existing helper:
from app.integrations.cli import _parse_port
...
"port": _parse_port(os.getenv("MARIADB_PORT", "3306").strip()),Prompt To Fix With AI
This is a comment left during a code review.
Path: app/integrations/verify.py
Line: 307
Comment:
**Bare `int()` crashes on invalid `MARIADB_PORT`**
If `MARIADB_HOST` is set and `MARIADB_PORT` contains a non-numeric value (e.g. `"localhost:3306"`, `"abc"`), `int(...)` raises `ValueError` with no surrounding try/except, crashing `resolve_effective_integrations()` entirely — breaking verification for all integrations, not just MariaDB. The parallel path in `node.py`'s `_load_env_integrations` avoids this by routing through `build_mariadb_config`, which handles coercion gracefully via `_normalize_port`.
Reuse the existing helper:
```python
from app.integrations.cli import _parse_port
...
"port": _parse_port(os.getenv("MARIADB_PORT", "3306").strip()),
```
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
Fixed — using _parse_port now which handles invalid values gracefully instead of bare int().
There was a problem hiding this comment.
Fixed — removed the circular import. Using inline safe parsing now instead of importing from cli.py.
VaibhavUpreti
left a comment
There was a problem hiding this comment.
Awesome job @yashksaini-coder 🚀 ! Thanks a lot for the reviews @Devesh36 !!!
|
@yashksaini-coder could you please create a new issue to document this in our list of integrations in the mintlify docs https://www.opensre.com/docs? |

What this does
Adds a first-class MariaDB integration so OpenSRE can directly query MariaDB instances during incident investigations — connection health, active queries, lock contention, slow queries, and replication status.
Why
Teams running MariaDB-backed services had no way to pull database-level evidence during incidents. This closes that gap with 5 production-safe, read-only investigation tools.
What's included
app/integrations/mariadb.pywith connection config, pymysql driver, and connectivity validationis_available/extract_paramsso tools only appear when MariaDB is configured and credentials auto-populateMARIADB_HOST,MARIADB_PORT,MARIADB_DATABASE,MARIADB_USERNAME,MARIADB_PASSWORD,MARIADB_SSLSafety
SHOW ALL SLAVES STATUSwithSHOW SLAVE STATUSfallback,performance_schemadisabled graceful handlingHow to test
MARIADB_HOST,MARIADB_DATABASE,MARIADB_USERNAME,MARIADB_PASSWORDin.envopensre integrations setup mariadbopensre integrations verify mariadbChecks
make lint— all passedmake typecheck— 298 source files, no issuesmake test-cov— all MariaDB tests pass (57 new tests)Closes #331