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.
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/CHANGELOG.md +42 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/PKG-INFO +59 -20
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/README.md +44 -19
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/THIRD_PARTY_NOTICES.md +23 -1
- {sqlguard_ninja-0.4.0/benchmarks/results/v1.1.0 → sqlguard_ninja-0.6.0/benchmarks/baselines}/native.json +1815 -1257
- sqlguard_ninja-0.6.0/benchmarks/datasets/v1/cases/09_mysql.yaml +143 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/datasets/v1/manifest.yaml +1 -1
- sqlguard_ninja-0.6.0/benchmarks/results/v1.2.0/agent-sql-guard.csv +1071 -0
- sqlguard_ninja-0.6.0/benchmarks/results/v1.2.0/agent-sql-guard.json +20729 -0
- sqlguard_ninja-0.6.0/benchmarks/results/v1.2.0/agent-sql-guard.md +112 -0
- sqlguard_ninja-0.6.0/benchmarks/results/v1.2.0/krish2105-sqlguard.csv +1071 -0
- sqlguard_ninja-0.6.0/benchmarks/results/v1.2.0/krish2105-sqlguard.json +20666 -0
- sqlguard_ninja-0.6.0/benchmarks/results/v1.2.0/krish2105-sqlguard.md +112 -0
- sqlguard_ninja-0.6.0/benchmarks/results/v1.2.0/native.csv +1071 -0
- sqlguard_ninja-0.6.0/benchmarks/results/v1.2.0/native.json +21042 -0
- sqlguard_ninja-0.6.0/benchmarks/results/v1.2.0/native.md +80 -0
- sqlguard_ninja-0.6.0/benchmarks/results/v1.2.0/sql-guardrail.csv +1071 -0
- sqlguard_ninja-0.6.0/benchmarks/results/v1.2.0/sql-guardrail.json +21348 -0
- sqlguard_ninja-0.6.0/benchmarks/results/v1.2.0/sql-guardrail.md +108 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/architecture/ARCHITECTURE_DECISIONS.md +20 -0
- sqlguard_ninja-0.6.0/docs/benchmarks/RESULTS_v1.2.md +63 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/development/IMPLEMENTATION_PROGRESS.md +3 -1
- sqlguard_ninja-0.6.0/docs/development/NEXT_ACTIONS.md +6 -0
- sqlguard_ninja-0.6.0/docs/development/TEST_EVIDENCE.md +21 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/development/progress.json +14 -8
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/guides/AGENT_INTEGRATION.md +21 -10
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/guides/CI_INTEGRATION.md +22 -0
- sqlguard_ninja-0.6.0/docs/guides/DATABASE_COMPATIBILITY.md +53 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/guides/MCP_INTEGRATION.md +1 -1
- sqlguard_ninja-0.6.0/docs/guides/OBSERVABILITY.md +133 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/guides/POLICY_REFERENCE.md +9 -3
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/guides/QUERY_COST.md +3 -2
- sqlguard_ninja-0.6.0/docs/releases/v0.5.0.md +20 -0
- sqlguard_ninja-0.6.0/docs/releases/v0.6.0.md +24 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/security/THREAT_MODEL.md +2 -0
- sqlguard_ninja-0.6.0/examples/observability/docker-compose.yml +47 -0
- sqlguard_ninja-0.6.0/examples/observability/grafana/provisioning/dashboards/sqlguard.yml +9 -0
- sqlguard_ninja-0.6.0/examples/observability/grafana/provisioning/datasources/prometheus.yml +9 -0
- sqlguard_ninja-0.6.0/examples/observability/prometheus.yml +6 -0
- sqlguard_ninja-0.6.0/examples/observability/smoke_check.py +42 -0
- sqlguard_ninja-0.6.0/examples/observability/synthetic_traffic.py +80 -0
- sqlguard_ninja-0.6.0/examples/sql/support_queries.sql +22 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/pyproject.toml +9 -2
- sqlguard_ninja-0.6.0/src/sqlguard_ninja/_version.py +1 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/benchmarking/fixtures.py +9 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/cli/main.py +93 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/core/analysis.py +1 -1
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/integrations/audit.py +42 -5
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/integrations/checkpoint.py +30 -2
- sqlguard_ninja-0.6.0/src/sqlguard_ninja/integrations/mysql.py +108 -0
- sqlguard_ninja-0.6.0/src/sqlguard_ninja/observability/__init__.py +17 -0
- sqlguard_ninja-0.6.0/src/sqlguard_ninja/observability/metrics.py +121 -0
- sqlguard_ninja-0.6.0/src/sqlguard_ninja/observability/telemetry.py +148 -0
- sqlguard_ninja-0.6.0/src/sqlguard_ninja/reporting/sarif.py +195 -0
- sqlguard_ninja-0.6.0/tests/data/sarif-schema-2.1.0.json +3389 -0
- sqlguard_ninja-0.6.0/tests/integration/test_mysql.py +117 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/unit/test_dataset.py +1 -1
- sqlguard_ninja-0.6.0/tests/unit/test_experimental_dialects.py +39 -0
- sqlguard_ninja-0.6.0/tests/unit/test_grafana_dashboard.py +84 -0
- sqlguard_ninja-0.6.0/tests/unit/test_mysql_binding.py +113 -0
- sqlguard_ninja-0.6.0/tests/unit/test_observability.py +381 -0
- sqlguard_ninja-0.4.0/docs/development/NEXT_ACTIONS.md +0 -6
- sqlguard_ninja-0.4.0/docs/development/TEST_EVIDENCE.md +0 -15
- sqlguard_ninja-0.4.0/src/sqlguard_ninja/_version.py +0 -1
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/.gitignore +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/LICENSE +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/datasets/external/README.md +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/datasets/v1/LABEL_CHANGES.yaml +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/datasets/v1/cases/01_destructive.yaml +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/datasets/v1/cases/02_multi_statement_and_formatting.yaml +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/datasets/v1/cases/03_table_and_column_access.yaml +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/datasets/v1/cases/04_privacy.yaml +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/datasets/v1/cases/05_tenant_isolation.yaml +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/datasets/v1/cases/06_cte_nested_unicode.yaml +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/datasets/v1/cases/07_legitimate_lookalike_cost_dialect.yaml +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/datasets/v1/cases/08_lineage.yaml +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/datasets/v1/generated/grant_matrix.yaml +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/datasets/v1/generated/label_matrix.yaml +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/datasets/v1/generated/tenant_matrix.yaml +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/datasets/v1/generated/transforms.yaml +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/policies/retail_saas.yaml +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.0.0/agent-sql-guard.json +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.0.0/agent-sql-guard.md +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.0.0/krish2105-sqlguard.json +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.0.0/krish2105-sqlguard.md +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.0.0/native.json +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.0.0/native.md +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.0.0/sql-guardrail.json +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.0.0/sql-guardrail.md +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.1.0/agent-sql-guard.csv +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.1.0/agent-sql-guard.json +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.1.0/agent-sql-guard.md +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.1.0/krish2105-sqlguard.csv +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.1.0/krish2105-sqlguard.json +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.1.0/krish2105-sqlguard.md +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.1.0/native.csv +0 -0
- {sqlguard_ninja-0.4.0/benchmarks/baselines → sqlguard_ninja-0.6.0/benchmarks/results/v1.1.0}/native.json +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.1.0/native.md +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.1.0/sql-guardrail.csv +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.1.0/sql-guardrail.json +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/benchmarks/results/v1.1.0/sql-guardrail.md +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/benchmarks/RESULTS_v1.1.md +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/benchmarks/RESULTS_v1.md +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/development/ARCHITECTURE_MAP.md +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/development/DECISION_LOG.md +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/development/UPGRADE_MASTER_PLAN.md +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/guides/BENCHMARK_BIAS_REVIEW.md +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/guides/BENCHMARK_METHODOLOGY.md +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/guides/POLICY_AS_CODE.md +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/release/FINAL_TECHNICAL_AUDIT.md +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/releases/v0.1.0.md +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/releases/v0.1.1.md +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/releases/v0.2.0.md +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/releases/v0.3.0.md +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/releases/v0.4.0.md +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/research/COMPETITIVE_ANALYSIS.md +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/docs/security/STATIC_ANALYSIS_LIMITS.md +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/examples/_shared.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/examples/fastapi/app.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/examples/github-actions/sql-security.yml +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/examples/langchain/guarded_tool_demo.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/examples/langgraph/real_llm_agent.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/examples/langgraph/sql_agent_demo.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/examples/postgresql/plan_inspection_demo.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/examples/sdk/quickstart.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/examples/sqlite/text_to_sql_demo.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/__init__.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/benchmarking/__init__.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/benchmarking/adapters.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/benchmarking/builtin.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/benchmarking/compare.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/benchmarking/dataset.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/benchmarking/metrics.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/benchmarking/runner.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/benchmarking/translate.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/benchmarking/workers/_protocol.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/benchmarking/workers/agent_sql_guard_worker.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/benchmarking/workers/krish_sqlguard_worker.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/benchmarking/workers/sql_guardrail_worker.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/cli/__init__.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/cli/config.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/cli/templates.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/core/__init__.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/core/findings.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/core/guard.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/core/lineage.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/core/rules/__init__.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/core/rules/access.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/core/rules/base.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/core/rules/catalog.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/core/rules/functions.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/core/rules/statements.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/core/rules/structure.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/core/rules/tenant.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/integrations/__init__.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/integrations/executors.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/integrations/fastapi.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/integrations/langchain.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/integrations/langgraph.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/mcp_server.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/policy/__init__.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/policy/inheritance.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/policy/model.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/policy/templates/analytics_readonly.yaml +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/policy/templates/minimal.yaml +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/policy/templates/multi_tenant_saas.yaml +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/policy/tools.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/privacy/__init__.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/privacy/rules.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/privacy/suggest.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/py.typed +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/query_cost/__init__.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/query_cost/postgres.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/query_cost/static.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/reporting/__init__.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/reporting/markdown.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/src/sqlguard_ninja/tenancy.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/__init__.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/conftest.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/integration/__init__.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/integration/test_corpus_sqlite_validation.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/integration/test_external_adapters.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/integration/test_frameworks.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/integration/test_mcp_server.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/integration/test_postgres.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/pg_support.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/property/__init__.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/property/test_guard_properties.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/security/__init__.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/security/test_agent_boundaries.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/security/test_corpus_native.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/security/test_tenant_rewrite.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/unit/__init__.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/unit/helpers.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/unit/test_benchmark_engine.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/unit/test_cli.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/unit/test_docs.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/unit/test_function_policy_mechanics.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/unit/test_lineage.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/unit/test_policy.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/unit/test_policy_inheritance.py +0 -0
- {sqlguard_ninja-0.4.0 → sqlguard_ninja-0.6.0}/tests/unit/test_policy_tools.py +0 -0
- {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.
|
|
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
|
|
185
|
-
result.findings
|
|
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,
|
|
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))
|
|
203
|
-
graph.add_conditional_edges(
|
|
204
|
-
|
|
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}})
|
|
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.
|
|
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.
|
|
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.
|
|
324
|
-
| sql-guardrail 0.5.2 | 98.
|
|
325
|
-
| agent-sql-guard 0.2.0 |
|
|
326
|
-
| krish2105/sqlguard 0.1.0 |
|
|
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
|
|
364
|
-
corpus,
|
|
365
|
-
writes,
|
|
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 **
|
|
394
|
-
|
|
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
|
|
125
|
-
result.findings
|
|
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,
|
|
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))
|
|
143
|
-
graph.add_conditional_edges(
|
|
144
|
-
|
|
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}})
|
|
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.
|
|
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.
|
|
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.
|
|
264
|
-
| sql-guardrail 0.5.2 | 98.
|
|
265
|
-
| agent-sql-guard 0.2.0 |
|
|
266
|
-
| krish2105/sqlguard 0.1.0 |
|
|
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
|
|
304
|
-
corpus,
|
|
305
|
-
writes,
|
|
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 **
|
|
334
|
-
|
|
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
|
|
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
|