sqlguard-ninja 0.3.0__tar.gz → 0.5.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (187) hide show
  1. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/CHANGELOG.md +30 -0
  2. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/PKG-INFO +49 -17
  3. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/README.md +40 -16
  4. {sqlguard_ninja-0.3.0/benchmarks/results/v1.1.0 → sqlguard_ninja-0.5.0/benchmarks/baselines}/native.json +1815 -1257
  5. sqlguard_ninja-0.5.0/benchmarks/datasets/v1/cases/09_mysql.yaml +143 -0
  6. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/benchmarks/datasets/v1/manifest.yaml +1 -1
  7. sqlguard_ninja-0.5.0/benchmarks/results/v1.2.0/agent-sql-guard.csv +1071 -0
  8. sqlguard_ninja-0.5.0/benchmarks/results/v1.2.0/agent-sql-guard.json +20729 -0
  9. sqlguard_ninja-0.5.0/benchmarks/results/v1.2.0/agent-sql-guard.md +112 -0
  10. sqlguard_ninja-0.5.0/benchmarks/results/v1.2.0/krish2105-sqlguard.csv +1071 -0
  11. sqlguard_ninja-0.5.0/benchmarks/results/v1.2.0/krish2105-sqlguard.json +20666 -0
  12. sqlguard_ninja-0.5.0/benchmarks/results/v1.2.0/krish2105-sqlguard.md +112 -0
  13. sqlguard_ninja-0.5.0/benchmarks/results/v1.2.0/native.csv +1071 -0
  14. sqlguard_ninja-0.5.0/benchmarks/results/v1.2.0/native.json +21042 -0
  15. sqlguard_ninja-0.5.0/benchmarks/results/v1.2.0/native.md +80 -0
  16. sqlguard_ninja-0.5.0/benchmarks/results/v1.2.0/sql-guardrail.csv +1071 -0
  17. sqlguard_ninja-0.5.0/benchmarks/results/v1.2.0/sql-guardrail.json +21348 -0
  18. sqlguard_ninja-0.5.0/benchmarks/results/v1.2.0/sql-guardrail.md +108 -0
  19. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/docs/architecture/ARCHITECTURE_DECISIONS.md +20 -0
  20. sqlguard_ninja-0.5.0/docs/benchmarks/RESULTS_v1.2.md +63 -0
  21. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/docs/development/IMPLEMENTATION_PROGRESS.md +3 -1
  22. sqlguard_ninja-0.5.0/docs/development/NEXT_ACTIONS.md +6 -0
  23. sqlguard_ninja-0.5.0/docs/development/TEST_EVIDENCE.md +18 -0
  24. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/docs/development/progress.json +14 -8
  25. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/docs/guides/AGENT_INTEGRATION.md +21 -10
  26. sqlguard_ninja-0.5.0/docs/guides/DATABASE_COMPATIBILITY.md +53 -0
  27. sqlguard_ninja-0.5.0/docs/guides/MCP_INTEGRATION.md +77 -0
  28. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/docs/guides/POLICY_REFERENCE.md +9 -3
  29. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/docs/guides/QUERY_COST.md +3 -2
  30. sqlguard_ninja-0.5.0/docs/releases/v0.4.0.md +20 -0
  31. sqlguard_ninja-0.5.0/docs/releases/v0.5.0.md +20 -0
  32. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/docs/security/THREAT_MODEL.md +2 -0
  33. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/pyproject.toml +6 -2
  34. sqlguard_ninja-0.5.0/src/sqlguard_ninja/_version.py +1 -0
  35. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/benchmarking/fixtures.py +9 -0
  36. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/cli/main.py +20 -0
  37. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/core/analysis.py +1 -1
  38. sqlguard_ninja-0.5.0/src/sqlguard_ninja/integrations/mysql.py +108 -0
  39. sqlguard_ninja-0.5.0/src/sqlguard_ninja/mcp_server.py +287 -0
  40. sqlguard_ninja-0.5.0/tests/integration/test_mcp_server.py +142 -0
  41. sqlguard_ninja-0.5.0/tests/integration/test_mysql.py +117 -0
  42. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/tests/unit/test_dataset.py +1 -1
  43. sqlguard_ninja-0.5.0/tests/unit/test_experimental_dialects.py +39 -0
  44. sqlguard_ninja-0.5.0/tests/unit/test_mysql_binding.py +113 -0
  45. sqlguard_ninja-0.3.0/docs/development/NEXT_ACTIONS.md +0 -5
  46. sqlguard_ninja-0.3.0/docs/development/TEST_EVIDENCE.md +0 -12
  47. sqlguard_ninja-0.3.0/src/sqlguard_ninja/_version.py +0 -1
  48. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/.gitignore +0 -0
  49. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/LICENSE +0 -0
  50. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/THIRD_PARTY_NOTICES.md +0 -0
  51. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/benchmarks/datasets/external/README.md +0 -0
  52. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/benchmarks/datasets/v1/LABEL_CHANGES.yaml +0 -0
  53. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/benchmarks/datasets/v1/cases/01_destructive.yaml +0 -0
  54. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/benchmarks/datasets/v1/cases/02_multi_statement_and_formatting.yaml +0 -0
  55. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/benchmarks/datasets/v1/cases/03_table_and_column_access.yaml +0 -0
  56. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/benchmarks/datasets/v1/cases/04_privacy.yaml +0 -0
  57. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/benchmarks/datasets/v1/cases/05_tenant_isolation.yaml +0 -0
  58. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/benchmarks/datasets/v1/cases/06_cte_nested_unicode.yaml +0 -0
  59. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/benchmarks/datasets/v1/cases/07_legitimate_lookalike_cost_dialect.yaml +0 -0
  60. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/benchmarks/datasets/v1/cases/08_lineage.yaml +0 -0
  61. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/benchmarks/datasets/v1/generated/grant_matrix.yaml +0 -0
  62. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/benchmarks/datasets/v1/generated/label_matrix.yaml +0 -0
  63. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/benchmarks/datasets/v1/generated/tenant_matrix.yaml +0 -0
  64. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/benchmarks/datasets/v1/generated/transforms.yaml +0 -0
  65. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/benchmarks/policies/retail_saas.yaml +0 -0
  66. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/benchmarks/results/v1.0.0/agent-sql-guard.json +0 -0
  67. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/benchmarks/results/v1.0.0/agent-sql-guard.md +0 -0
  68. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/benchmarks/results/v1.0.0/krish2105-sqlguard.json +0 -0
  69. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/benchmarks/results/v1.0.0/krish2105-sqlguard.md +0 -0
  70. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/benchmarks/results/v1.0.0/native.json +0 -0
  71. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/benchmarks/results/v1.0.0/native.md +0 -0
  72. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/benchmarks/results/v1.0.0/sql-guardrail.json +0 -0
  73. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/benchmarks/results/v1.0.0/sql-guardrail.md +0 -0
  74. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/benchmarks/results/v1.1.0/agent-sql-guard.csv +0 -0
  75. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/benchmarks/results/v1.1.0/agent-sql-guard.json +0 -0
  76. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/benchmarks/results/v1.1.0/agent-sql-guard.md +0 -0
  77. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/benchmarks/results/v1.1.0/krish2105-sqlguard.csv +0 -0
  78. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/benchmarks/results/v1.1.0/krish2105-sqlguard.json +0 -0
  79. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/benchmarks/results/v1.1.0/krish2105-sqlguard.md +0 -0
  80. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/benchmarks/results/v1.1.0/native.csv +0 -0
  81. {sqlguard_ninja-0.3.0/benchmarks/baselines → sqlguard_ninja-0.5.0/benchmarks/results/v1.1.0}/native.json +0 -0
  82. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/benchmarks/results/v1.1.0/native.md +0 -0
  83. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/benchmarks/results/v1.1.0/sql-guardrail.csv +0 -0
  84. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/benchmarks/results/v1.1.0/sql-guardrail.json +0 -0
  85. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/benchmarks/results/v1.1.0/sql-guardrail.md +0 -0
  86. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/docs/benchmarks/RESULTS_v1.1.md +0 -0
  87. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/docs/benchmarks/RESULTS_v1.md +0 -0
  88. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/docs/development/ARCHITECTURE_MAP.md +0 -0
  89. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/docs/development/DECISION_LOG.md +0 -0
  90. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/docs/development/UPGRADE_MASTER_PLAN.md +0 -0
  91. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/docs/guides/BENCHMARK_BIAS_REVIEW.md +0 -0
  92. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/docs/guides/BENCHMARK_METHODOLOGY.md +0 -0
  93. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/docs/guides/CI_INTEGRATION.md +0 -0
  94. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/docs/guides/POLICY_AS_CODE.md +0 -0
  95. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/docs/release/FINAL_TECHNICAL_AUDIT.md +0 -0
  96. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/docs/releases/v0.1.0.md +0 -0
  97. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/docs/releases/v0.1.1.md +0 -0
  98. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/docs/releases/v0.2.0.md +0 -0
  99. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/docs/releases/v0.3.0.md +0 -0
  100. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/docs/research/COMPETITIVE_ANALYSIS.md +0 -0
  101. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/docs/security/STATIC_ANALYSIS_LIMITS.md +0 -0
  102. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/examples/_shared.py +0 -0
  103. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/examples/fastapi/app.py +0 -0
  104. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/examples/github-actions/sql-security.yml +0 -0
  105. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/examples/langchain/guarded_tool_demo.py +0 -0
  106. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/examples/langgraph/real_llm_agent.py +0 -0
  107. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/examples/langgraph/sql_agent_demo.py +0 -0
  108. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/examples/postgresql/plan_inspection_demo.py +0 -0
  109. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/examples/sdk/quickstart.py +0 -0
  110. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/examples/sqlite/text_to_sql_demo.py +0 -0
  111. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/__init__.py +0 -0
  112. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/benchmarking/__init__.py +0 -0
  113. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/benchmarking/adapters.py +0 -0
  114. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/benchmarking/builtin.py +0 -0
  115. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/benchmarking/compare.py +0 -0
  116. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/benchmarking/dataset.py +0 -0
  117. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/benchmarking/metrics.py +0 -0
  118. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/benchmarking/runner.py +0 -0
  119. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/benchmarking/translate.py +0 -0
  120. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/benchmarking/workers/_protocol.py +0 -0
  121. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/benchmarking/workers/agent_sql_guard_worker.py +0 -0
  122. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/benchmarking/workers/krish_sqlguard_worker.py +0 -0
  123. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/benchmarking/workers/sql_guardrail_worker.py +0 -0
  124. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/cli/__init__.py +0 -0
  125. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/cli/config.py +0 -0
  126. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/cli/templates.py +0 -0
  127. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/core/__init__.py +0 -0
  128. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/core/findings.py +0 -0
  129. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/core/guard.py +0 -0
  130. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/core/lineage.py +0 -0
  131. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/core/rules/__init__.py +0 -0
  132. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/core/rules/access.py +0 -0
  133. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/core/rules/base.py +0 -0
  134. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/core/rules/catalog.py +0 -0
  135. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/core/rules/functions.py +0 -0
  136. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/core/rules/statements.py +0 -0
  137. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/core/rules/structure.py +0 -0
  138. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/core/rules/tenant.py +0 -0
  139. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/integrations/__init__.py +0 -0
  140. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/integrations/audit.py +0 -0
  141. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/integrations/checkpoint.py +0 -0
  142. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/integrations/executors.py +0 -0
  143. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/integrations/fastapi.py +0 -0
  144. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/integrations/langchain.py +0 -0
  145. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/integrations/langgraph.py +0 -0
  146. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/policy/__init__.py +0 -0
  147. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/policy/inheritance.py +0 -0
  148. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/policy/model.py +0 -0
  149. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/policy/templates/analytics_readonly.yaml +0 -0
  150. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/policy/templates/minimal.yaml +0 -0
  151. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/policy/templates/multi_tenant_saas.yaml +0 -0
  152. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/policy/tools.py +0 -0
  153. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/privacy/__init__.py +0 -0
  154. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/privacy/rules.py +0 -0
  155. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/privacy/suggest.py +0 -0
  156. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/py.typed +0 -0
  157. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/query_cost/__init__.py +0 -0
  158. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/query_cost/postgres.py +0 -0
  159. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/query_cost/static.py +0 -0
  160. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/reporting/__init__.py +0 -0
  161. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/reporting/markdown.py +0 -0
  162. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/src/sqlguard_ninja/tenancy.py +0 -0
  163. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/tests/__init__.py +0 -0
  164. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/tests/conftest.py +0 -0
  165. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/tests/integration/__init__.py +0 -0
  166. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/tests/integration/test_corpus_sqlite_validation.py +0 -0
  167. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/tests/integration/test_external_adapters.py +0 -0
  168. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/tests/integration/test_frameworks.py +0 -0
  169. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/tests/integration/test_postgres.py +0 -0
  170. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/tests/pg_support.py +0 -0
  171. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/tests/property/__init__.py +0 -0
  172. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/tests/property/test_guard_properties.py +0 -0
  173. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/tests/security/__init__.py +0 -0
  174. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/tests/security/test_agent_boundaries.py +0 -0
  175. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/tests/security/test_corpus_native.py +0 -0
  176. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/tests/security/test_tenant_rewrite.py +0 -0
  177. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/tests/unit/__init__.py +0 -0
  178. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/tests/unit/helpers.py +0 -0
  179. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/tests/unit/test_benchmark_engine.py +0 -0
  180. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/tests/unit/test_cli.py +0 -0
  181. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/tests/unit/test_docs.py +0 -0
  182. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/tests/unit/test_function_policy_mechanics.py +0 -0
  183. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/tests/unit/test_lineage.py +0 -0
  184. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/tests/unit/test_policy.py +0 -0
  185. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/tests/unit/test_policy_inheritance.py +0 -0
  186. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/tests/unit/test_policy_tools.py +0 -0
  187. {sqlguard_ninja-0.3.0 → sqlguard_ninja-0.5.0}/tests/unit/test_rules.py +0 -0
@@ -3,6 +3,36 @@
3
3
  All notable changes are documented here. The project follows
4
4
  [Semantic Versioning](https://semver.org/); before 1.0, minor versions may change the API.
5
5
 
6
+ ## [0.5.0] — 2026-10-24
7
+
8
+ ### Added
9
+ * **MySQL 8** as a tested dialect within a documented scope: `sqlguard_ninja.integrations.mysql`
10
+ (`mysql_executor`: read-only transaction, `MAX_EXECUTION_TIME`, rollback; `bind_placeholders`:
11
+ AST-based binding of named placeholders, ADR-013), extra `[mysql]` (PyMySQL), and a MySQL 8.4
12
+ service-container CI job that executes every MySQL `allow` case as a SELECT-only account.
13
+ * Corpus **1.2.0**: 26 MySQL cases (`cases/09_mysql.yaml`); results in
14
+ `docs/benchmarks/RESULTS_v1.2.md`.
15
+ * `docs/guides/DATABASE_COMPATIBILITY.md`: compatibility matrix. SQL Server and Oracle are
16
+ parser-level experimental with smoke tests; they are not accepted by the MCP server.
17
+ * The MCP server accepts `mysql` as a dialect.
18
+
19
+ ### Security
20
+ * MySQL identifiers are compared exactly and never case-folded (fail closed). String values
21
+ containing a backslash or NUL are refused at binding time. `mysql_executor` refuses sessions
22
+ whose `sql_mode` changes lexing (`ANSI_QUOTES`, `NO_BACKSLASH_ESCAPES`, `PIPES_AS_CONCAT`,
23
+ `HIGH_NOT_PRECEDENCE`, `ANSI`); threat model T18.
24
+
25
+ ## [0.4.0] — 2026-10-24
26
+
27
+ ### Added
28
+ * **MCP server** (`sqlninja mcp`, `sqlguard_ninja.mcp_server`, extra `[mcp]` on the official
29
+ MCP Python SDK 2.x). Tools: `validate_sql`, `explain_policy_decision`,
30
+ `inspect_query_cost`, `get_policy_capabilities`. The role and tenant are fixed server-side,
31
+ there is no execution and no database connection, internal detail is withheld, ungranted
32
+ tables and columns are not disclosed, input is size-capped, and calls are rate-limited.
33
+ * An end-to-end test drives the real server over stdio with the SDK's `ClientSession`.
34
+ * Docs: `docs/guides/MCP_INTEGRATION.md`; threat model T17.
35
+
6
36
  ## [0.3.0] — 2026-10-24
7
37
 
8
38
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: sqlguard-ninja
3
- Version: 0.3.0
3
+ Version: 0.5.0
4
4
  Summary: Security testing, policy enforcement, agent integration, privacy analysis and CI benchmarking for LLM-generated SQL.
5
5
  Project-URL: Homepage, https://github.com/Pratik653/SQLGuard_Ninjapy
6
6
  Project-URL: Documentation, https://github.com/Pratik653/SQLGuard_Ninjapy/tree/main/docs
@@ -29,7 +29,9 @@ Provides-Extra: all
29
29
  Requires-Dist: fastapi>=0.110; extra == 'all'
30
30
  Requires-Dist: langchain-core>=0.3; extra == 'all'
31
31
  Requires-Dist: langgraph>=0.2; extra == 'all'
32
+ Requires-Dist: mcp<3,>=2.3; extra == 'all'
32
33
  Requires-Dist: psycopg[binary]>=3.1; extra == 'all'
34
+ Requires-Dist: pymysql>=1.1; extra == 'all'
33
35
  Provides-Extra: dev
34
36
  Requires-Dist: build>=1.2; extra == 'dev'
35
37
  Requires-Dist: fastapi>=0.110; extra == 'dev'
@@ -37,8 +39,10 @@ Requires-Dist: httpx>=0.27; extra == 'dev'
37
39
  Requires-Dist: hypothesis>=6.100; extra == 'dev'
38
40
  Requires-Dist: langchain-core>=0.3; extra == 'dev'
39
41
  Requires-Dist: langgraph>=0.2; extra == 'dev'
42
+ Requires-Dist: mcp<3,>=2.3; extra == 'dev'
40
43
  Requires-Dist: mypy>=1.10; extra == 'dev'
41
44
  Requires-Dist: psycopg[binary]>=3.1; extra == 'dev'
45
+ Requires-Dist: pymysql>=1.1; extra == 'dev'
42
46
  Requires-Dist: pytest-cov>=5.0; extra == 'dev'
43
47
  Requires-Dist: pytest>=8.0; extra == 'dev'
44
48
  Requires-Dist: ruff>=0.6; extra == 'dev'
@@ -50,6 +54,10 @@ Requires-Dist: langchain-core>=0.3; extra == 'langchain'
50
54
  Provides-Extra: langgraph
51
55
  Requires-Dist: langchain-core>=0.3; extra == 'langgraph'
52
56
  Requires-Dist: langgraph>=0.2; extra == 'langgraph'
57
+ Provides-Extra: mcp
58
+ Requires-Dist: mcp<3,>=2.3; extra == 'mcp'
59
+ Provides-Extra: mysql
60
+ Requires-Dist: pymysql>=1.1; extra == 'mysql'
53
61
  Provides-Extra: postgres
54
62
  Requires-Dist: psycopg[binary]>=3.1; extra == 'postgres'
55
63
  Description-Content-Type: text/markdown
@@ -177,8 +185,8 @@ result = guard.validate(
177
185
  role="hr_analyst",
178
186
  dialect="postgres",
179
187
  )
180
- result.allowed # True
181
- result.findings # () - structured Finding objects with rule_id, action, message, remediation
188
+ result.allowed # True
189
+ result.findings # () - structured Finding objects with rule_id, action, message, remediation
182
190
 
183
191
  guard.validate("SELECT full_name, salary FROM employees", role="hr_analyst").explain()
184
192
  # DENY:
@@ -191,16 +199,21 @@ guard.validate("SELECT full_name, salary FROM employees", role="hr_analyst").exp
191
199
  ```python
192
200
  from sqlguard_ninja.integrations import RequestContext, SQLCheckpoint
193
201
  from sqlguard_ninja.integrations.langgraph import (
194
- CONTEXT_KEY, make_execute_node, make_guard_node, route_after_guard)
202
+ CONTEXT_KEY,
203
+ make_execute_node,
204
+ make_guard_node,
205
+ route_after_guard,
206
+ )
195
207
 
196
208
  checkpoint = SQLCheckpoint(guard, mode="block", max_denied_attempts=3)
197
209
  graph.add_node("guard", make_guard_node(checkpoint))
198
- graph.add_node("execute", make_execute_node(checkpoint, executor)) # re-validates
199
- graph.add_conditional_edges("guard", route_after_guard(3),
200
- {"execute": "execute", "revise": "generate", "end": END})
210
+ graph.add_node("execute", make_execute_node(checkpoint, executor)) # re-validates
211
+ graph.add_conditional_edges(
212
+ "guard", route_after_guard(3), {"execute": "execute", "revise": "generate", "end": END}
213
+ )
201
214
 
202
215
  ctx = RequestContext(principal=user.id, role=user.role, tenant_id=user.tenant_id)
203
- app.invoke(state, config={"configurable": {CONTEXT_KEY: ctx}}) # nodes cannot alter config
216
+ app.invoke(state, config={"configurable": {CONTEXT_KEY: ctx}}) # nodes cannot alter config
204
217
  ```
205
218
 
206
219
  More in [AGENT_INTEGRATION.md](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/AGENT_INTEGRATION.md): the LangChain tool (its
@@ -263,6 +276,20 @@ Optional: `SQLCheckpoint(..., rewrite_tenant_filters=True)` adds missing tenant
263
276
  through the AST and executes only the re-validated rewrite. See
264
277
  [POLICY_AS_CODE.md](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/POLICY_AS_CODE.md).
265
278
 
279
+ ## MCP server
280
+
281
+ Let MCP-compatible agents check SQL against your policy before running it anywhere:
282
+
283
+ ```bash
284
+ python -m pip install "sqlguard-ninja[mcp]"
285
+ sqlninja mcp --policy builtin:retail_saas --role support_analyst --tenant 1
286
+ ```
287
+
288
+ The four tools are `validate_sql`, `explain_policy_decision`, `inspect_query_cost` and
289
+ `get_policy_capabilities`. The role and tenant are fixed server-side, the server never connects
290
+ to a database, and it exposes no execution tool. Tested with the official MCP Python SDK
291
+ client over stdio. See [MCP_INTEGRATION.md](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/MCP_INTEGRATION.md).
292
+
266
293
  ## Query cost analysis
267
294
 
268
295
  Every validation includes an explainable static score that uses the catalog's
@@ -280,8 +307,10 @@ rolled-back transaction:
280
307
 
281
308
  ```python
282
309
  from sqlguard_ninja.query_cost.postgres import PostgresPlanInspector
310
+
283
311
  report = PostgresPlanInspector(guard, lambda: psycopg.connect(READER_DSN)).inspect(
284
- sql, role="support_analyst", context={"tenant_id": 1})
312
+ sql, role="support_analyst", context={"tenant_id": 1}
313
+ )
285
314
  report.total_cost, report.plan_rows, report.static.score, report.findings
286
315
  ```
287
316
 
@@ -296,16 +325,16 @@ sqlninja benchmark run --dataset builtin:v1 --adapter external:sql-guardrail
296
325
  sqlninja benchmark compare --baseline benchmarks/baselines/native.json --candidate results/latest.json
297
326
  ```
298
327
 
299
- Results for corpus v1.1.0 (551 cases, 1,044 evaluations; SQLGuard Ninja 0.2.0; Windows 11,
328
+ Results for corpus v1.2.0 (577 cases, 1,070 evaluations; SQLGuard Ninja 0.5.0; Windows 11,
300
329
  Python 3.11). Intervals are 95% Wilson intervals. Details, CSV and raw files:
301
- [RESULTS_v1.1.md](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/benchmarks/RESULTS_v1.1.md).
330
+ [RESULTS_v1.2.md](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/benchmarks/RESULTS_v1.2.md).
302
331
 
303
332
  | Validator | Recall (95% CI) | Precision | F1 | FPR (95% CI) | Recall / FPR within declared capability | p95 ms |
304
333
  |---|---:|---:|---:|---:|---:|---:|
305
- | SQLGuard Ninja 0.2.0 | 100.0% (99.4–100.0) | 100.0% | 1.000 | 0.0% (0.0–0.9) | 100.0% / 0.0% | 3.33 |
306
- | sql-guardrail 0.5.2 | 98.7% (97.4–99.3) | 85.1% | 0.914 | 24.1% (20.3–28.3) | 98.3% / 19.7% | 2.63 |
307
- | agent-sql-guard 0.2.0 | 67.3% (63.4–70.9) | 85.2% | 0.752 | 16.3% (13.1–20.0) | 89.4% / 17.7% | 1.87 |
308
- | krish2105/sqlguard 0.1.0 | 65.3% (61.4–69.0) | 89.6% | 0.755 | 10.5% (8.0–13.8) | 83.5% / 5.2% | 1.95 |
334
+ | SQLGuard Ninja 0.5.0 | 100.0% (99.4–100.0) | 100.0% | 1.000 | 0.0% (0.0–0.9) | 100.0% / 0.0% | 3.36 |
335
+ | sql-guardrail 0.5.2 | 98.2% (96.9–99.0) | 84.7% | 0.909 | 24.8% (21.1–29.0) | 98.3% / 19.7% | 1.84 |
336
+ | agent-sql-guard 0.2.0 | 66.8% (63.0–70.4) | 85.1% | 0.748 | 16.3% (13.2–20.0) | 89.4% / 17.7% | 1.44 |
337
+ | krish2105/sqlguard 0.1.0 | 64.8% (61.0–68.5) | 89.4% | 0.752 | 10.7% (8.2–14.0) | 83.5% / 5.2% | 1.42 |
309
338
 
310
339
  **All of these are internal results.** The corpus was written by this project, alongside the
311
340
  engine. The native 100% shows consistency with the documented semantics, not independent
@@ -358,6 +387,7 @@ writes, more tested dialects, and SARIF output. Details in [ROADMAP.md](https://
358
387
 
359
388
  * [Policy reference](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/POLICY_REFERENCE.md)
360
389
  * [Policy as code](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/POLICY_AS_CODE.md)
390
+ * [MCP integration](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/MCP_INTEGRATION.md)
361
391
  * [Agent integration](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/AGENT_INTEGRATION.md)
362
392
  * [Query cost](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/QUERY_COST.md)
363
393
  * [CI integration](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/CI_INTEGRATION.md)
@@ -371,8 +401,10 @@ writes, more tested dialects, and SARIF output. Details in [ROADMAP.md](https://
371
401
  ## Supported versions
372
402
 
373
403
  * Python 3.11, 3.12, 3.13 (CI matrix on Linux and Windows).
374
- * SQL dialects: **PostgreSQL** (tested against PostgreSQL 16) and **SQLite**. Other sqlglot
375
- dialects parse but are experimental and untested.
404
+ * SQL dialects: **PostgreSQL** (tested against PostgreSQL 16), **SQLite**, and **MySQL 8**
405
+ (tested against MySQL 8.4 in CI, within the documented scope: identifier case is not folded,
406
+ named placeholders only). SQL Server and Oracle are parser-level **experimental**; others are
407
+ untested. See the [compatibility matrix](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/DATABASE_COMPATIBILITY.md).
376
408
 
377
409
  ## Development
378
410
 
@@ -121,8 +121,8 @@ result = guard.validate(
121
121
  role="hr_analyst",
122
122
  dialect="postgres",
123
123
  )
124
- result.allowed # True
125
- result.findings # () - structured Finding objects with rule_id, action, message, remediation
124
+ result.allowed # True
125
+ result.findings # () - structured Finding objects with rule_id, action, message, remediation
126
126
 
127
127
  guard.validate("SELECT full_name, salary FROM employees", role="hr_analyst").explain()
128
128
  # DENY:
@@ -135,16 +135,21 @@ guard.validate("SELECT full_name, salary FROM employees", role="hr_analyst").exp
135
135
  ```python
136
136
  from sqlguard_ninja.integrations import RequestContext, SQLCheckpoint
137
137
  from sqlguard_ninja.integrations.langgraph import (
138
- CONTEXT_KEY, make_execute_node, make_guard_node, route_after_guard)
138
+ CONTEXT_KEY,
139
+ make_execute_node,
140
+ make_guard_node,
141
+ route_after_guard,
142
+ )
139
143
 
140
144
  checkpoint = SQLCheckpoint(guard, mode="block", max_denied_attempts=3)
141
145
  graph.add_node("guard", make_guard_node(checkpoint))
142
- graph.add_node("execute", make_execute_node(checkpoint, executor)) # re-validates
143
- graph.add_conditional_edges("guard", route_after_guard(3),
144
- {"execute": "execute", "revise": "generate", "end": END})
146
+ graph.add_node("execute", make_execute_node(checkpoint, executor)) # re-validates
147
+ graph.add_conditional_edges(
148
+ "guard", route_after_guard(3), {"execute": "execute", "revise": "generate", "end": END}
149
+ )
145
150
 
146
151
  ctx = RequestContext(principal=user.id, role=user.role, tenant_id=user.tenant_id)
147
- app.invoke(state, config={"configurable": {CONTEXT_KEY: ctx}}) # nodes cannot alter config
152
+ app.invoke(state, config={"configurable": {CONTEXT_KEY: ctx}}) # nodes cannot alter config
148
153
  ```
149
154
 
150
155
  More in [AGENT_INTEGRATION.md](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/AGENT_INTEGRATION.md): the LangChain tool (its
@@ -207,6 +212,20 @@ Optional: `SQLCheckpoint(..., rewrite_tenant_filters=True)` adds missing tenant
207
212
  through the AST and executes only the re-validated rewrite. See
208
213
  [POLICY_AS_CODE.md](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/POLICY_AS_CODE.md).
209
214
 
215
+ ## MCP server
216
+
217
+ Let MCP-compatible agents check SQL against your policy before running it anywhere:
218
+
219
+ ```bash
220
+ python -m pip install "sqlguard-ninja[mcp]"
221
+ sqlninja mcp --policy builtin:retail_saas --role support_analyst --tenant 1
222
+ ```
223
+
224
+ The four tools are `validate_sql`, `explain_policy_decision`, `inspect_query_cost` and
225
+ `get_policy_capabilities`. The role and tenant are fixed server-side, the server never connects
226
+ to a database, and it exposes no execution tool. Tested with the official MCP Python SDK
227
+ client over stdio. See [MCP_INTEGRATION.md](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/MCP_INTEGRATION.md).
228
+
210
229
  ## Query cost analysis
211
230
 
212
231
  Every validation includes an explainable static score that uses the catalog's
@@ -224,8 +243,10 @@ rolled-back transaction:
224
243
 
225
244
  ```python
226
245
  from sqlguard_ninja.query_cost.postgres import PostgresPlanInspector
246
+
227
247
  report = PostgresPlanInspector(guard, lambda: psycopg.connect(READER_DSN)).inspect(
228
- sql, role="support_analyst", context={"tenant_id": 1})
248
+ sql, role="support_analyst", context={"tenant_id": 1}
249
+ )
229
250
  report.total_cost, report.plan_rows, report.static.score, report.findings
230
251
  ```
231
252
 
@@ -240,16 +261,16 @@ sqlninja benchmark run --dataset builtin:v1 --adapter external:sql-guardrail
240
261
  sqlninja benchmark compare --baseline benchmarks/baselines/native.json --candidate results/latest.json
241
262
  ```
242
263
 
243
- Results for corpus v1.1.0 (551 cases, 1,044 evaluations; SQLGuard Ninja 0.2.0; Windows 11,
264
+ Results for corpus v1.2.0 (577 cases, 1,070 evaluations; SQLGuard Ninja 0.5.0; Windows 11,
244
265
  Python 3.11). Intervals are 95% Wilson intervals. Details, CSV and raw files:
245
- [RESULTS_v1.1.md](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/benchmarks/RESULTS_v1.1.md).
266
+ [RESULTS_v1.2.md](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/benchmarks/RESULTS_v1.2.md).
246
267
 
247
268
  | Validator | Recall (95% CI) | Precision | F1 | FPR (95% CI) | Recall / FPR within declared capability | p95 ms |
248
269
  |---|---:|---:|---:|---:|---:|---:|
249
- | SQLGuard Ninja 0.2.0 | 100.0% (99.4–100.0) | 100.0% | 1.000 | 0.0% (0.0–0.9) | 100.0% / 0.0% | 3.33 |
250
- | sql-guardrail 0.5.2 | 98.7% (97.4–99.3) | 85.1% | 0.914 | 24.1% (20.3–28.3) | 98.3% / 19.7% | 2.63 |
251
- | agent-sql-guard 0.2.0 | 67.3% (63.4–70.9) | 85.2% | 0.752 | 16.3% (13.1–20.0) | 89.4% / 17.7% | 1.87 |
252
- | krish2105/sqlguard 0.1.0 | 65.3% (61.4–69.0) | 89.6% | 0.755 | 10.5% (8.0–13.8) | 83.5% / 5.2% | 1.95 |
270
+ | SQLGuard Ninja 0.5.0 | 100.0% (99.4–100.0) | 100.0% | 1.000 | 0.0% (0.0–0.9) | 100.0% / 0.0% | 3.36 |
271
+ | sql-guardrail 0.5.2 | 98.2% (96.9–99.0) | 84.7% | 0.909 | 24.8% (21.1–29.0) | 98.3% / 19.7% | 1.84 |
272
+ | agent-sql-guard 0.2.0 | 66.8% (63.0–70.4) | 85.1% | 0.748 | 16.3% (13.2–20.0) | 89.4% / 17.7% | 1.44 |
273
+ | krish2105/sqlguard 0.1.0 | 64.8% (61.0–68.5) | 89.4% | 0.752 | 10.7% (8.2–14.0) | 83.5% / 5.2% | 1.42 |
253
274
 
254
275
  **All of these are internal results.** The corpus was written by this project, alongside the
255
276
  engine. The native 100% shows consistency with the documented semantics, not independent
@@ -302,6 +323,7 @@ writes, more tested dialects, and SARIF output. Details in [ROADMAP.md](https://
302
323
 
303
324
  * [Policy reference](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/POLICY_REFERENCE.md)
304
325
  * [Policy as code](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/POLICY_AS_CODE.md)
326
+ * [MCP integration](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/MCP_INTEGRATION.md)
305
327
  * [Agent integration](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/AGENT_INTEGRATION.md)
306
328
  * [Query cost](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/QUERY_COST.md)
307
329
  * [CI integration](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/CI_INTEGRATION.md)
@@ -315,8 +337,10 @@ writes, more tested dialects, and SARIF output. Details in [ROADMAP.md](https://
315
337
  ## Supported versions
316
338
 
317
339
  * Python 3.11, 3.12, 3.13 (CI matrix on Linux and Windows).
318
- * SQL dialects: **PostgreSQL** (tested against PostgreSQL 16) and **SQLite**. Other sqlglot
319
- dialects parse but are experimental and untested.
340
+ * SQL dialects: **PostgreSQL** (tested against PostgreSQL 16), **SQLite**, and **MySQL 8**
341
+ (tested against MySQL 8.4 in CI, within the documented scope: identifier case is not folded,
342
+ named placeholders only). SQL Server and Oracle are parser-level **experimental**; others are
343
+ untested. See the [compatibility matrix](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/DATABASE_COMPATIBILITY.md).
320
344
 
321
345
  ## Development
322
346