sqlguard-ninja 0.4.0__tar.gz → 0.6.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 (203) hide show
  1. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/CHANGELOG.md +42 -0
  2. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/PKG-INFO +59 -20
  3. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/README.md +44 -19
  4. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/THIRD_PARTY_NOTICES.md +23 -1
  5. {sqlguard_ninja-0.4.0/benchmarks/results/v1.1.0 → sqlguard_ninja-0.6.0/benchmarks/baselines}/native.json +1815 -1257
  6. sqlguard_ninja-0.6.0/benchmarks/datasets/v1/cases/09_mysql.yaml +143 -0
  7. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/datasets/v1/manifest.yaml +1 -1
  8. sqlguard_ninja-0.6.0/benchmarks/results/v1.2.0/agent-sql-guard.csv +1071 -0
  9. sqlguard_ninja-0.6.0/benchmarks/results/v1.2.0/agent-sql-guard.json +20729 -0
  10. sqlguard_ninja-0.6.0/benchmarks/results/v1.2.0/agent-sql-guard.md +112 -0
  11. sqlguard_ninja-0.6.0/benchmarks/results/v1.2.0/krish2105-sqlguard.csv +1071 -0
  12. sqlguard_ninja-0.6.0/benchmarks/results/v1.2.0/krish2105-sqlguard.json +20666 -0
  13. sqlguard_ninja-0.6.0/benchmarks/results/v1.2.0/krish2105-sqlguard.md +112 -0
  14. sqlguard_ninja-0.6.0/benchmarks/results/v1.2.0/native.csv +1071 -0
  15. sqlguard_ninja-0.6.0/benchmarks/results/v1.2.0/native.json +21042 -0
  16. sqlguard_ninja-0.6.0/benchmarks/results/v1.2.0/native.md +80 -0
  17. sqlguard_ninja-0.6.0/benchmarks/results/v1.2.0/sql-guardrail.csv +1071 -0
  18. sqlguard_ninja-0.6.0/benchmarks/results/v1.2.0/sql-guardrail.json +21348 -0
  19. sqlguard_ninja-0.6.0/benchmarks/results/v1.2.0/sql-guardrail.md +108 -0
  20. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/architecture/ARCHITECTURE_DECISIONS.md +20 -0
  21. sqlguard_ninja-0.6.0/docs/benchmarks/RESULTS_v1.2.md +63 -0
  22. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/development/IMPLEMENTATION_PROGRESS.md +3 -1
  23. sqlguard_ninja-0.6.0/docs/development/NEXT_ACTIONS.md +6 -0
  24. sqlguard_ninja-0.6.0/docs/development/TEST_EVIDENCE.md +21 -0
  25. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/development/progress.json +14 -8
  26. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/guides/AGENT_INTEGRATION.md +21 -10
  27. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/guides/CI_INTEGRATION.md +22 -0
  28. sqlguard_ninja-0.6.0/docs/guides/DATABASE_COMPATIBILITY.md +53 -0
  29. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/guides/MCP_INTEGRATION.md +1 -1
  30. sqlguard_ninja-0.6.0/docs/guides/OBSERVABILITY.md +133 -0
  31. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/guides/POLICY_REFERENCE.md +9 -3
  32. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/guides/QUERY_COST.md +3 -2
  33. sqlguard_ninja-0.6.0/docs/releases/v0.5.0.md +20 -0
  34. sqlguard_ninja-0.6.0/docs/releases/v0.6.0.md +24 -0
  35. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/security/THREAT_MODEL.md +2 -0
  36. sqlguard_ninja-0.6.0/examples/observability/docker-compose.yml +47 -0
  37. sqlguard_ninja-0.6.0/examples/observability/grafana/provisioning/dashboards/sqlguard.yml +9 -0
  38. sqlguard_ninja-0.6.0/examples/observability/grafana/provisioning/datasources/prometheus.yml +9 -0
  39. sqlguard_ninja-0.6.0/examples/observability/prometheus.yml +6 -0
  40. sqlguard_ninja-0.6.0/examples/observability/smoke_check.py +42 -0
  41. sqlguard_ninja-0.6.0/examples/observability/synthetic_traffic.py +80 -0
  42. sqlguard_ninja-0.6.0/examples/sql/support_queries.sql +22 -0
  43. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/pyproject.toml +9 -2
  44. sqlguard_ninja-0.6.0/src/sqlguard_ninja/_version.py +1 -0
  45. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/benchmarking/fixtures.py +9 -0
  46. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/cli/main.py +93 -0
  47. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/core/analysis.py +1 -1
  48. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/integrations/audit.py +42 -5
  49. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/integrations/checkpoint.py +30 -2
  50. sqlguard_ninja-0.6.0/src/sqlguard_ninja/integrations/mysql.py +108 -0
  51. sqlguard_ninja-0.6.0/src/sqlguard_ninja/observability/__init__.py +17 -0
  52. sqlguard_ninja-0.6.0/src/sqlguard_ninja/observability/metrics.py +121 -0
  53. sqlguard_ninja-0.6.0/src/sqlguard_ninja/observability/telemetry.py +148 -0
  54. sqlguard_ninja-0.6.0/src/sqlguard_ninja/reporting/sarif.py +195 -0
  55. sqlguard_ninja-0.6.0/tests/data/sarif-schema-2.1.0.json +3389 -0
  56. sqlguard_ninja-0.6.0/tests/integration/test_mysql.py +117 -0
  57. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/unit/test_dataset.py +1 -1
  58. sqlguard_ninja-0.6.0/tests/unit/test_experimental_dialects.py +39 -0
  59. sqlguard_ninja-0.6.0/tests/unit/test_grafana_dashboard.py +84 -0
  60. sqlguard_ninja-0.6.0/tests/unit/test_mysql_binding.py +113 -0
  61. sqlguard_ninja-0.6.0/tests/unit/test_observability.py +381 -0
  62. sqlguard_ninja-0.4.0/docs/development/NEXT_ACTIONS.md +0 -6
  63. sqlguard_ninja-0.4.0/docs/development/TEST_EVIDENCE.md +0 -15
  64. sqlguard_ninja-0.4.0/src/sqlguard_ninja/_version.py +0 -1
  65. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/.gitignore +0 -0
  66. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/LICENSE +0 -0
  67. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/datasets/external/README.md +0 -0
  68. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/datasets/v1/LABEL_CHANGES.yaml +0 -0
  69. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/datasets/v1/cases/01_destructive.yaml +0 -0
  70. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/datasets/v1/cases/02_multi_statement_and_formatting.yaml +0 -0
  71. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/datasets/v1/cases/03_table_and_column_access.yaml +0 -0
  72. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/datasets/v1/cases/04_privacy.yaml +0 -0
  73. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/datasets/v1/cases/05_tenant_isolation.yaml +0 -0
  74. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/datasets/v1/cases/06_cte_nested_unicode.yaml +0 -0
  75. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/datasets/v1/cases/07_legitimate_lookalike_cost_dialect.yaml +0 -0
  76. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/datasets/v1/cases/08_lineage.yaml +0 -0
  77. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/datasets/v1/generated/grant_matrix.yaml +0 -0
  78. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/datasets/v1/generated/label_matrix.yaml +0 -0
  79. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/datasets/v1/generated/tenant_matrix.yaml +0 -0
  80. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/datasets/v1/generated/transforms.yaml +0 -0
  81. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/policies/retail_saas.yaml +0 -0
  82. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.0.0/agent-sql-guard.json +0 -0
  83. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.0.0/agent-sql-guard.md +0 -0
  84. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.0.0/krish2105-sqlguard.json +0 -0
  85. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.0.0/krish2105-sqlguard.md +0 -0
  86. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.0.0/native.json +0 -0
  87. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.0.0/native.md +0 -0
  88. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.0.0/sql-guardrail.json +0 -0
  89. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.0.0/sql-guardrail.md +0 -0
  90. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.1.0/agent-sql-guard.csv +0 -0
  91. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.1.0/agent-sql-guard.json +0 -0
  92. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.1.0/agent-sql-guard.md +0 -0
  93. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.1.0/krish2105-sqlguard.csv +0 -0
  94. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.1.0/krish2105-sqlguard.json +0 -0
  95. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.1.0/krish2105-sqlguard.md +0 -0
  96. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.1.0/native.csv +0 -0
  97. {sqlguard_ninja-0.4.0/benchmarks/baselines → sqlguard_ninja-0.6.0/benchmarks/results/v1.1.0}/native.json +0 -0
  98. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.1.0/native.md +0 -0
  99. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.1.0/sql-guardrail.csv +0 -0
  100. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.1.0/sql-guardrail.json +0 -0
  101. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.1.0/sql-guardrail.md +0 -0
  102. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/benchmarks/RESULTS_v1.1.md +0 -0
  103. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/benchmarks/RESULTS_v1.md +0 -0
  104. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/development/ARCHITECTURE_MAP.md +0 -0
  105. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/development/DECISION_LOG.md +0 -0
  106. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/development/UPGRADE_MASTER_PLAN.md +0 -0
  107. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/guides/BENCHMARK_BIAS_REVIEW.md +0 -0
  108. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/guides/BENCHMARK_METHODOLOGY.md +0 -0
  109. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/guides/POLICY_AS_CODE.md +0 -0
  110. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/release/FINAL_TECHNICAL_AUDIT.md +0 -0
  111. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/releases/v0.1.0.md +0 -0
  112. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/releases/v0.1.1.md +0 -0
  113. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/releases/v0.2.0.md +0 -0
  114. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/releases/v0.3.0.md +0 -0
  115. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/releases/v0.4.0.md +0 -0
  116. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/research/COMPETITIVE_ANALYSIS.md +0 -0
  117. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/security/STATIC_ANALYSIS_LIMITS.md +0 -0
  118. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/examples/_shared.py +0 -0
  119. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/examples/fastapi/app.py +0 -0
  120. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/examples/github-actions/sql-security.yml +0 -0
  121. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/examples/langchain/guarded_tool_demo.py +0 -0
  122. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/examples/langgraph/real_llm_agent.py +0 -0
  123. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/examples/langgraph/sql_agent_demo.py +0 -0
  124. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/examples/postgresql/plan_inspection_demo.py +0 -0
  125. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/examples/sdk/quickstart.py +0 -0
  126. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/examples/sqlite/text_to_sql_demo.py +0 -0
  127. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/__init__.py +0 -0
  128. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/benchmarking/__init__.py +0 -0
  129. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/benchmarking/adapters.py +0 -0
  130. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/benchmarking/builtin.py +0 -0
  131. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/benchmarking/compare.py +0 -0
  132. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/benchmarking/dataset.py +0 -0
  133. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/benchmarking/metrics.py +0 -0
  134. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/benchmarking/runner.py +0 -0
  135. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/benchmarking/translate.py +0 -0
  136. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/benchmarking/workers/_protocol.py +0 -0
  137. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/benchmarking/workers/agent_sql_guard_worker.py +0 -0
  138. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/benchmarking/workers/krish_sqlguard_worker.py +0 -0
  139. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/benchmarking/workers/sql_guardrail_worker.py +0 -0
  140. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/cli/__init__.py +0 -0
  141. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/cli/config.py +0 -0
  142. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/cli/templates.py +0 -0
  143. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/core/__init__.py +0 -0
  144. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/core/findings.py +0 -0
  145. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/core/guard.py +0 -0
  146. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/core/lineage.py +0 -0
  147. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/core/rules/__init__.py +0 -0
  148. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/core/rules/access.py +0 -0
  149. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/core/rules/base.py +0 -0
  150. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/core/rules/catalog.py +0 -0
  151. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/core/rules/functions.py +0 -0
  152. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/core/rules/statements.py +0 -0
  153. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/core/rules/structure.py +0 -0
  154. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/core/rules/tenant.py +0 -0
  155. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/integrations/__init__.py +0 -0
  156. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/integrations/executors.py +0 -0
  157. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/integrations/fastapi.py +0 -0
  158. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/integrations/langchain.py +0 -0
  159. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/integrations/langgraph.py +0 -0
  160. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/mcp_server.py +0 -0
  161. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/policy/__init__.py +0 -0
  162. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/policy/inheritance.py +0 -0
  163. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/policy/model.py +0 -0
  164. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/policy/templates/analytics_readonly.yaml +0 -0
  165. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/policy/templates/minimal.yaml +0 -0
  166. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/policy/templates/multi_tenant_saas.yaml +0 -0
  167. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/policy/tools.py +0 -0
  168. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/privacy/__init__.py +0 -0
  169. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/privacy/rules.py +0 -0
  170. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/privacy/suggest.py +0 -0
  171. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/py.typed +0 -0
  172. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/query_cost/__init__.py +0 -0
  173. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/query_cost/postgres.py +0 -0
  174. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/query_cost/static.py +0 -0
  175. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/reporting/__init__.py +0 -0
  176. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/reporting/markdown.py +0 -0
  177. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/tenancy.py +0 -0
  178. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/__init__.py +0 -0
  179. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/conftest.py +0 -0
  180. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/integration/__init__.py +0 -0
  181. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/integration/test_corpus_sqlite_validation.py +0 -0
  182. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/integration/test_external_adapters.py +0 -0
  183. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/integration/test_frameworks.py +0 -0
  184. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/integration/test_mcp_server.py +0 -0
  185. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/integration/test_postgres.py +0 -0
  186. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/pg_support.py +0 -0
  187. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/property/__init__.py +0 -0
  188. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/property/test_guard_properties.py +0 -0
  189. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/security/__init__.py +0 -0
  190. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/security/test_agent_boundaries.py +0 -0
  191. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/security/test_corpus_native.py +0 -0
  192. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/security/test_tenant_rewrite.py +0 -0
  193. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/unit/__init__.py +0 -0
  194. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/unit/helpers.py +0 -0
  195. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/unit/test_benchmark_engine.py +0 -0
  196. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/unit/test_cli.py +0 -0
  197. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/unit/test_docs.py +0 -0
  198. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/unit/test_function_policy_mechanics.py +0 -0
  199. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/unit/test_lineage.py +0 -0
  200. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/unit/test_policy.py +0 -0
  201. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/unit/test_policy_inheritance.py +0 -0
  202. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/unit/test_policy_tools.py +0 -0
  203. {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/unit/test_rules.py +0 -0
@@ -3,6 +3,48 @@
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.6.0] — 2026-10-24
7
+
8
+ ### Added
9
+ * **Observability** (`sqlguard_ninja.observability`, extras `[otel]` and `[prometheus]`):
10
+ * `Telemetry` and `InstrumentedGuard` emit OpenTelemetry spans `sqlguard.checkpoint` and
11
+ `sqlguard.validate`.
12
+ * `GuardMetrics` exports Prometheus counters and histograms for decisions, findings,
13
+ latency, errors, resource-limit rejections, checkpoint outcomes and policy identity.
14
+ * `SQLCheckpoint(telemetry=...)` instruments its guard automatically.
15
+ * **SARIF 2.1.0**: `sqlninja scan PATH... --format sarif|json|text --fail-on deny|review|never`.
16
+ It validates every statement in SQL files, with stable fingerprints. Tests and CI validate the
17
+ output against the OASIS schema.
18
+ * **Grafana dashboard** `deploy/grafana/sqlguard-ninja.json`, and a Prometheus + Grafana +
19
+ synthetic-traffic stack (`examples/observability/`). A new CI job runs that stack.
20
+ * Audit events gain `schema_version` and `rate_limited`. New
21
+ `SQLCheckpoint(principal_hmac_key=...)` option to pseudonymise principals.
22
+
23
+ ### Security
24
+ * `redact_sql` now redacts hex, bit, byte (`E''`), dollar-quoted, Unicode (`U&''`) and
25
+ national (`N''`) strings and whole `INTERVAL` expressions. Previously these could reach
26
+ `sql_redacted` in audit logs. Comments are dropped, and if any literal token survives,
27
+ redacted SQL is withheld. See threat model T19.
28
+
29
+ ## [0.5.0] — 2026-10-24
30
+
31
+ ### Added
32
+ * **MySQL 8** as a tested dialect within a documented scope: `sqlguard_ninja.integrations.mysql`
33
+ (`mysql_executor`: read-only transaction, `MAX_EXECUTION_TIME`, rollback; `bind_placeholders`:
34
+ AST-based binding of named placeholders, ADR-013), extra `[mysql]` (PyMySQL), and a MySQL 8.4
35
+ service-container CI job that executes every MySQL `allow` case as a SELECT-only account.
36
+ * Corpus **1.2.0**: 26 MySQL cases (`cases/09_mysql.yaml`); results in
37
+ `docs/benchmarks/RESULTS_v1.2.md`.
38
+ * `docs/guides/DATABASE_COMPATIBILITY.md`: compatibility matrix. SQL Server and Oracle are
39
+ parser-level experimental with smoke tests; they are not accepted by the MCP server.
40
+ * The MCP server accepts `mysql` as a dialect.
41
+
42
+ ### Security
43
+ * MySQL identifiers are compared exactly and never case-folded (fail closed). String values
44
+ containing a backslash or NUL are refused at binding time. `mysql_executor` refuses sessions
45
+ whose `sql_mode` changes lexing (`ANSI_QUOTES`, `NO_BACKSLASH_ESCAPES`, `PIPES_AS_CONCAT`,
46
+ `HIGH_NOT_PRECEDENCE`, `ANSI`); threat model T18.
47
+
6
48
  ## [0.4.0] — 2026-10-24
7
49
 
8
50
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: sqlguard-ninja
3
- Version: 0.4.0
3
+ Version: 0.6.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
@@ -30,17 +30,25 @@ 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
32
  Requires-Dist: mcp<3,>=2.3; extra == 'all'
33
+ Requires-Dist: opentelemetry-api>=1.25; extra == 'all'
34
+ Requires-Dist: prometheus-client>=0.20; extra == 'all'
33
35
  Requires-Dist: psycopg[binary]>=3.1; extra == 'all'
36
+ Requires-Dist: pymysql>=1.1; extra == 'all'
34
37
  Provides-Extra: dev
35
38
  Requires-Dist: build>=1.2; extra == 'dev'
36
39
  Requires-Dist: fastapi>=0.110; extra == 'dev'
37
40
  Requires-Dist: httpx>=0.27; extra == 'dev'
38
41
  Requires-Dist: hypothesis>=6.100; extra == 'dev'
42
+ Requires-Dist: jsonschema>=4.20; extra == 'dev'
39
43
  Requires-Dist: langchain-core>=0.3; extra == 'dev'
40
44
  Requires-Dist: langgraph>=0.2; extra == 'dev'
41
45
  Requires-Dist: mcp<3,>=2.3; extra == 'dev'
42
46
  Requires-Dist: mypy>=1.10; extra == 'dev'
47
+ Requires-Dist: opentelemetry-api>=1.25; extra == 'dev'
48
+ Requires-Dist: opentelemetry-sdk>=1.25; extra == 'dev'
49
+ Requires-Dist: prometheus-client>=0.20; extra == 'dev'
43
50
  Requires-Dist: psycopg[binary]>=3.1; extra == 'dev'
51
+ Requires-Dist: pymysql>=1.1; extra == 'dev'
44
52
  Requires-Dist: pytest-cov>=5.0; extra == 'dev'
45
53
  Requires-Dist: pytest>=8.0; extra == 'dev'
46
54
  Requires-Dist: ruff>=0.6; extra == 'dev'
@@ -54,8 +62,14 @@ Requires-Dist: langchain-core>=0.3; extra == 'langgraph'
54
62
  Requires-Dist: langgraph>=0.2; extra == 'langgraph'
55
63
  Provides-Extra: mcp
56
64
  Requires-Dist: mcp<3,>=2.3; extra == 'mcp'
65
+ Provides-Extra: mysql
66
+ Requires-Dist: pymysql>=1.1; extra == 'mysql'
67
+ Provides-Extra: otel
68
+ Requires-Dist: opentelemetry-api>=1.25; extra == 'otel'
57
69
  Provides-Extra: postgres
58
70
  Requires-Dist: psycopg[binary]>=3.1; extra == 'postgres'
71
+ Provides-Extra: prometheus
72
+ Requires-Dist: prometheus-client>=0.20; extra == 'prometheus'
59
73
  Description-Content-Type: text/markdown
60
74
 
61
75
  # SQLGuard Ninja
@@ -181,8 +195,8 @@ result = guard.validate(
181
195
  role="hr_analyst",
182
196
  dialect="postgres",
183
197
  )
184
- result.allowed # True
185
- result.findings # () - structured Finding objects with rule_id, action, message, remediation
198
+ result.allowed # True
199
+ result.findings # () - structured Finding objects with rule_id, action, message, remediation
186
200
 
187
201
  guard.validate("SELECT full_name, salary FROM employees", role="hr_analyst").explain()
188
202
  # DENY:
@@ -195,16 +209,21 @@ guard.validate("SELECT full_name, salary FROM employees", role="hr_analyst").exp
195
209
  ```python
196
210
  from sqlguard_ninja.integrations import RequestContext, SQLCheckpoint
197
211
  from sqlguard_ninja.integrations.langgraph import (
198
- CONTEXT_KEY, make_execute_node, make_guard_node, route_after_guard)
212
+ CONTEXT_KEY,
213
+ make_execute_node,
214
+ make_guard_node,
215
+ route_after_guard,
216
+ )
199
217
 
200
218
  checkpoint = SQLCheckpoint(guard, mode="block", max_denied_attempts=3)
201
219
  graph.add_node("guard", make_guard_node(checkpoint))
202
- graph.add_node("execute", make_execute_node(checkpoint, executor)) # re-validates
203
- graph.add_conditional_edges("guard", route_after_guard(3),
204
- {"execute": "execute", "revise": "generate", "end": END})
220
+ graph.add_node("execute", make_execute_node(checkpoint, executor)) # re-validates
221
+ graph.add_conditional_edges(
222
+ "guard", route_after_guard(3), {"execute": "execute", "revise": "generate", "end": END}
223
+ )
205
224
 
206
225
  ctx = RequestContext(principal=user.id, role=user.role, tenant_id=user.tenant_id)
207
- app.invoke(state, config={"configurable": {CONTEXT_KEY: ctx}}) # nodes cannot alter config
226
+ app.invoke(state, config={"configurable": {CONTEXT_KEY: ctx}}) # nodes cannot alter config
208
227
  ```
209
228
 
210
229
  More in [AGENT_INTEGRATION.md](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/AGENT_INTEGRATION.md): the LangChain tool (its
@@ -281,6 +300,20 @@ The four tools are `validate_sql`, `explain_policy_decision`, `inspect_query_cos
281
300
  to a database, and it exposes no execution tool. Tested with the official MCP Python SDK
282
301
  client over stdio. See [MCP_INTEGRATION.md](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/MCP_INTEGRATION.md).
283
302
 
303
+ ## Observability and SARIF
304
+
305
+ ```bash
306
+ python -m pip install "sqlguard-ninja[otel,prometheus]"
307
+ sqlninja scan sql/ --policy policy.yaml --role reporting --tenant 1 --format sarif --output sqlninja.sarif
308
+ ```
309
+
310
+ `Telemetry(tracer=..., metrics=GuardMetrics())` adds OpenTelemetry spans and Prometheus metrics
311
+ to the checkpoint: decisions, findings by rule, latency, errors, resource-limit rejections and
312
+ checkpoint outcomes. By default no signal contains SQL text, literals, request-context values,
313
+ tenant ids or principals, and tests check this with canary values. A Grafana dashboard
314
+ (`deploy/grafana/`) and a synthetic-traffic Prometheus/Grafana stack are included. SARIF output
315
+ validates against the OASIS 2.1.0 schema. See [OBSERVABILITY.md](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/OBSERVABILITY.md).
316
+
284
317
  ## Query cost analysis
285
318
 
286
319
  Every validation includes an explainable static score that uses the catalog's
@@ -298,8 +331,10 @@ rolled-back transaction:
298
331
 
299
332
  ```python
300
333
  from sqlguard_ninja.query_cost.postgres import PostgresPlanInspector
334
+
301
335
  report = PostgresPlanInspector(guard, lambda: psycopg.connect(READER_DSN)).inspect(
302
- sql, role="support_analyst", context={"tenant_id": 1})
336
+ sql, role="support_analyst", context={"tenant_id": 1}
337
+ )
303
338
  report.total_cost, report.plan_rows, report.static.score, report.findings
304
339
  ```
305
340
 
@@ -314,16 +349,16 @@ sqlninja benchmark run --dataset builtin:v1 --adapter external:sql-guardrail
314
349
  sqlninja benchmark compare --baseline benchmarks/baselines/native.json --candidate results/latest.json
315
350
  ```
316
351
 
317
- Results for corpus v1.1.0 (551 cases, 1,044 evaluations; SQLGuard Ninja 0.2.0; Windows 11,
352
+ Results for corpus v1.2.0 (577 cases, 1,070 evaluations; SQLGuard Ninja 0.5.0; Windows 11,
318
353
  Python 3.11). Intervals are 95% Wilson intervals. Details, CSV and raw files:
319
- [RESULTS_v1.1.md](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/benchmarks/RESULTS_v1.1.md).
354
+ [RESULTS_v1.2.md](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/benchmarks/RESULTS_v1.2.md).
320
355
 
321
356
  | Validator | Recall (95% CI) | Precision | F1 | FPR (95% CI) | Recall / FPR within declared capability | p95 ms |
322
357
  |---|---:|---:|---:|---:|---:|---:|
323
- | 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 |
324
- | 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 |
325
- | 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 |
326
- | 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 |
358
+ | 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 |
359
+ | 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 |
360
+ | 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 |
361
+ | 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 |
327
362
 
328
363
  **All of these are internal results.** The corpus was written by this project, alongside the
329
364
  engine. The native 100% shows consistency with the documented semantics, not independent
@@ -360,9 +395,9 @@ the [benchmark bias review](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/m
360
395
 
361
396
  ## Roadmap
362
397
 
363
- Next: restricted-function and system-catalog benchmark cases, an independent held-out
364
- corpus, lineage-aware aggregate checks, and tenant predicate push-down. Later: governed
365
- writes, more tested dialects, and SARIF output. Details in [ROADMAP.md](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/ROADMAP.md).
398
+ Next: restricted-function and system-catalog benchmark cases (issue #5), an independent
399
+ held-out corpus (issue #6), an interactive demo and a hardened deployment reference. Later:
400
+ governed writes, and database-verified SQL Server and Oracle support. Details in [ROADMAP.md](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/ROADMAP.md).
366
401
 
367
402
  ## Links
368
403
 
@@ -380,6 +415,8 @@ writes, more tested dialects, and SARIF output. Details in [ROADMAP.md](https://
380
415
  * [Agent integration](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/AGENT_INTEGRATION.md)
381
416
  * [Query cost](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/QUERY_COST.md)
382
417
  * [CI integration](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/CI_INTEGRATION.md)
418
+ * [Observability and SARIF](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/OBSERVABILITY.md)
419
+ * [Database compatibility](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/DATABASE_COMPATIBILITY.md)
383
420
  * [Benchmark methodology](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/BENCHMARK_METHODOLOGY.md)
384
421
  * [Threat model](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/security/THREAT_MODEL.md)
385
422
  * [Limits of static SQL analysis and dialect support](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/security/STATIC_ANALYSIS_LIMITS.md)
@@ -390,8 +427,10 @@ writes, more tested dialects, and SARIF output. Details in [ROADMAP.md](https://
390
427
  ## Supported versions
391
428
 
392
429
  * Python 3.11, 3.12, 3.13 (CI matrix on Linux and Windows).
393
- * SQL dialects: **PostgreSQL** (tested against PostgreSQL 16) and **SQLite**. Other sqlglot
394
- dialects parse but are experimental and untested.
430
+ * SQL dialects: **PostgreSQL** (tested against PostgreSQL 16), **SQLite**, and **MySQL 8**
431
+ (tested against MySQL 8.4 in CI, within the documented scope: identifier case is not folded,
432
+ named placeholders only). SQL Server and Oracle are parser-level **experimental**; others are
433
+ untested. See the [compatibility matrix](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/DATABASE_COMPATIBILITY.md).
395
434
 
396
435
  ## Development
397
436
 
@@ -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
@@ -221,6 +226,20 @@ The four tools are `validate_sql`, `explain_policy_decision`, `inspect_query_cos
221
226
  to a database, and it exposes no execution tool. Tested with the official MCP Python SDK
222
227
  client over stdio. See [MCP_INTEGRATION.md](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/MCP_INTEGRATION.md).
223
228
 
229
+ ## Observability and SARIF
230
+
231
+ ```bash
232
+ python -m pip install "sqlguard-ninja[otel,prometheus]"
233
+ sqlninja scan sql/ --policy policy.yaml --role reporting --tenant 1 --format sarif --output sqlninja.sarif
234
+ ```
235
+
236
+ `Telemetry(tracer=..., metrics=GuardMetrics())` adds OpenTelemetry spans and Prometheus metrics
237
+ to the checkpoint: decisions, findings by rule, latency, errors, resource-limit rejections and
238
+ checkpoint outcomes. By default no signal contains SQL text, literals, request-context values,
239
+ tenant ids or principals, and tests check this with canary values. A Grafana dashboard
240
+ (`deploy/grafana/`) and a synthetic-traffic Prometheus/Grafana stack are included. SARIF output
241
+ validates against the OASIS 2.1.0 schema. See [OBSERVABILITY.md](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/OBSERVABILITY.md).
242
+
224
243
  ## Query cost analysis
225
244
 
226
245
  Every validation includes an explainable static score that uses the catalog's
@@ -238,8 +257,10 @@ rolled-back transaction:
238
257
 
239
258
  ```python
240
259
  from sqlguard_ninja.query_cost.postgres import PostgresPlanInspector
260
+
241
261
  report = PostgresPlanInspector(guard, lambda: psycopg.connect(READER_DSN)).inspect(
242
- sql, role="support_analyst", context={"tenant_id": 1})
262
+ sql, role="support_analyst", context={"tenant_id": 1}
263
+ )
243
264
  report.total_cost, report.plan_rows, report.static.score, report.findings
244
265
  ```
245
266
 
@@ -254,16 +275,16 @@ sqlninja benchmark run --dataset builtin:v1 --adapter external:sql-guardrail
254
275
  sqlninja benchmark compare --baseline benchmarks/baselines/native.json --candidate results/latest.json
255
276
  ```
256
277
 
257
- Results for corpus v1.1.0 (551 cases, 1,044 evaluations; SQLGuard Ninja 0.2.0; Windows 11,
278
+ Results for corpus v1.2.0 (577 cases, 1,070 evaluations; SQLGuard Ninja 0.5.0; Windows 11,
258
279
  Python 3.11). Intervals are 95% Wilson intervals. Details, CSV and raw files:
259
- [RESULTS_v1.1.md](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/benchmarks/RESULTS_v1.1.md).
280
+ [RESULTS_v1.2.md](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/benchmarks/RESULTS_v1.2.md).
260
281
 
261
282
  | Validator | Recall (95% CI) | Precision | F1 | FPR (95% CI) | Recall / FPR within declared capability | p95 ms |
262
283
  |---|---:|---:|---:|---:|---:|---:|
263
- | 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 |
264
- | 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 |
265
- | 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 |
266
- | 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 |
284
+ | 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 |
285
+ | 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 |
286
+ | 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 |
287
+ | 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 |
267
288
 
268
289
  **All of these are internal results.** The corpus was written by this project, alongside the
269
290
  engine. The native 100% shows consistency with the documented semantics, not independent
@@ -300,9 +321,9 @@ the [benchmark bias review](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/m
300
321
 
301
322
  ## Roadmap
302
323
 
303
- Next: restricted-function and system-catalog benchmark cases, an independent held-out
304
- corpus, lineage-aware aggregate checks, and tenant predicate push-down. Later: governed
305
- writes, more tested dialects, and SARIF output. Details in [ROADMAP.md](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/ROADMAP.md).
324
+ Next: restricted-function and system-catalog benchmark cases (issue #5), an independent
325
+ held-out corpus (issue #6), an interactive demo and a hardened deployment reference. Later:
326
+ governed writes, and database-verified SQL Server and Oracle support. Details in [ROADMAP.md](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/ROADMAP.md).
306
327
 
307
328
  ## Links
308
329
 
@@ -320,6 +341,8 @@ writes, more tested dialects, and SARIF output. Details in [ROADMAP.md](https://
320
341
  * [Agent integration](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/AGENT_INTEGRATION.md)
321
342
  * [Query cost](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/QUERY_COST.md)
322
343
  * [CI integration](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/CI_INTEGRATION.md)
344
+ * [Observability and SARIF](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/OBSERVABILITY.md)
345
+ * [Database compatibility](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/DATABASE_COMPATIBILITY.md)
323
346
  * [Benchmark methodology](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/BENCHMARK_METHODOLOGY.md)
324
347
  * [Threat model](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/security/THREAT_MODEL.md)
325
348
  * [Limits of static SQL analysis and dialect support](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/security/STATIC_ANALYSIS_LIMITS.md)
@@ -330,8 +353,10 @@ writes, more tested dialects, and SARIF output. Details in [ROADMAP.md](https://
330
353
  ## Supported versions
331
354
 
332
355
  * Python 3.11, 3.12, 3.13 (CI matrix on Linux and Windows).
333
- * SQL dialects: **PostgreSQL** (tested against PostgreSQL 16) and **SQLite**. Other sqlglot
334
- dialects parse but are experimental and untested.
356
+ * SQL dialects: **PostgreSQL** (tested against PostgreSQL 16), **SQLite**, and **MySQL 8**
357
+ (tested against MySQL 8.4 in CI, within the documented scope: identifier case is not folded,
358
+ named placeholders only). SQL Server and Oracle are parser-level **experimental**; others are
359
+ untested. See the [compatibility matrix](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/DATABASE_COMPATIBILITY.md).
335
360
 
336
361
  ## Development
337
362
 
@@ -1,7 +1,8 @@
1
1
  # Third-party notices
2
2
 
3
3
  SQLGuard Ninja is licensed under Apache-2.0. **It does not vendor or copy third-party source
4
- code.** The projects below are used as ordinary dependencies, installed by the package
4
+ code.** The only third-party file in the repository is a test fixture, the SARIF schema
5
+ (below). The projects below are used as ordinary dependencies, installed by the package
5
6
  manager under their own licences. Licences were read from installed package metadata on
6
7
  2026-10-24. Always check the version you install.
7
8
 
@@ -21,6 +22,10 @@ manager under their own licences. Licences were read from installed package meta
21
22
  | `langgraph` | langgraph | 1.2.17 | MIT |
22
23
  | `fastapi` | fastapi / starlette | 0.162.0 / 1.9.0 | MIT / BSD-3-Clause |
23
24
  | `postgres` | psycopg (+ psycopg-binary) | 3.3.6 | LGPL-3.0-only |
25
+ | `mcp` | mcp (official MCP Python SDK) | 2.3.0 | MIT |
26
+ | `mysql` | PyMySQL | 1.2.3 | MIT |
27
+ | `otel` | opentelemetry-api | 1.45.1 | Apache-2.0 |
28
+ | `prometheus` | prometheus-client | 0.26.0 | Apache-2.0 AND BSD-2-Clause |
24
29
 
25
30
  psycopg is LGPL-3.0. SQLGuard Ninja only imports it at runtime when the `postgres` extra is
26
31
  installed. It is not modified or bundled, which is compatible with distributing SQLGuard Ninja
@@ -33,6 +38,23 @@ mypy (MIT), build (MIT). `pgserver` is optionally used for local PostgreSQL test
33
38
  declared dependency, and its package metadata on PyPI does not declare a licence. It bundles
34
39
  PostgreSQL binaries (PostgreSQL License).
35
40
 
41
+ Tests also use jsonschema (MIT) and opentelemetry-sdk (Apache-2.0).
42
+
43
+ ## Test fixture: SARIF 2.1.0 JSON schema
44
+
45
+ `tests/data/sarif-schema-2.1.0.json` is the unmodified OASIS SARIF 2.1.0 (Errata 01) schema,
46
+ downloaded from
47
+ https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/schemas/sarif-schema-2.1.0.json
48
+ (SHA-256 `c3b4bb2d6093897483348925aaa73af03b3e3f4bd4ca38cef26dcb4212a2682e`). It is used only to
49
+ validate SARIF output in tests and is not part of the wheel.
50
+
51
+ > Copyright © OASIS Open 2020. All Rights Reserved. This document and translations of it may be
52
+ > copied and furnished to others, and derivative works that comment on or otherwise explain it
53
+ > or assist in its implementation may be prepared, copied, published, and distributed, in whole
54
+ > or in part, without restriction of any kind, provided that the above copyright notice and this
55
+ > section are included on all such copies and derivative works. (OASIS IPR Policy notice; see
56
+ > https://www.oasis-open.org/policies-guidelines/ipr/)
57
+
36
58
  ## External validators used for benchmarking only
37
59
 
38
60
  Installed into isolated virtual environments by `scripts/setup_external_adapters.py`, never