sqlguard-ninja 0.1.1__tar.gz → 0.3.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 (161) hide show
  1. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/CHANGELOG.md +45 -0
  2. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/PKG-INFO +40 -20
  3. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/README.md +39 -19
  4. {sqlguard_ninja-0.1.1/benchmarks/results/v1.0.0 → sqlguard_ninja-0.3.0/benchmarks/baselines}/native.json +4844 -1315
  5. sqlguard_ninja-0.3.0/benchmarks/datasets/v1/LABEL_CHANGES.yaml +22 -0
  6. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/benchmarks/datasets/v1/cases/04_privacy.yaml +5 -4
  7. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/benchmarks/datasets/v1/cases/05_tenant_isolation.yaml +5 -2
  8. sqlguard_ninja-0.3.0/benchmarks/datasets/v1/cases/08_lineage.yaml +150 -0
  9. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/benchmarks/datasets/v1/manifest.yaml +1 -1
  10. sqlguard_ninja-0.3.0/benchmarks/results/v1.1.0/agent-sql-guard.csv +1045 -0
  11. sqlguard_ninja-0.3.0/benchmarks/results/v1.1.0/agent-sql-guard.json +20184 -0
  12. sqlguard_ninja-0.3.0/benchmarks/results/v1.1.0/agent-sql-guard.md +110 -0
  13. sqlguard_ninja-0.3.0/benchmarks/results/v1.1.0/krish2105-sqlguard.csv +1045 -0
  14. sqlguard_ninja-0.3.0/benchmarks/results/v1.1.0/krish2105-sqlguard.json +20121 -0
  15. sqlguard_ninja-0.3.0/benchmarks/results/v1.1.0/krish2105-sqlguard.md +110 -0
  16. sqlguard_ninja-0.3.0/benchmarks/results/v1.1.0/native.csv +1045 -0
  17. sqlguard_ninja-0.3.0/benchmarks/results/v1.1.0/native.json +20484 -0
  18. sqlguard_ninja-0.3.0/benchmarks/results/v1.1.0/native.md +78 -0
  19. sqlguard_ninja-0.3.0/benchmarks/results/v1.1.0/sql-guardrail.csv +1045 -0
  20. sqlguard_ninja-0.3.0/benchmarks/results/v1.1.0/sql-guardrail.json +20779 -0
  21. sqlguard_ninja-0.3.0/benchmarks/results/v1.1.0/sql-guardrail.md +103 -0
  22. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/docs/architecture/ARCHITECTURE_DECISIONS.md +19 -0
  23. sqlguard_ninja-0.3.0/docs/benchmarks/RESULTS_v1.1.md +48 -0
  24. sqlguard_ninja-0.3.0/docs/development/ARCHITECTURE_MAP.md +47 -0
  25. sqlguard_ninja-0.3.0/docs/development/DECISION_LOG.md +9 -0
  26. sqlguard_ninja-0.3.0/docs/development/IMPLEMENTATION_PROGRESS.md +11 -0
  27. sqlguard_ninja-0.3.0/docs/development/NEXT_ACTIONS.md +5 -0
  28. sqlguard_ninja-0.3.0/docs/development/TEST_EVIDENCE.md +12 -0
  29. sqlguard_ninja-0.3.0/docs/development/UPGRADE_MASTER_PLAN.md +25 -0
  30. sqlguard_ninja-0.3.0/docs/development/progress.json +110 -0
  31. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/docs/guides/AGENT_INTEGRATION.md +3 -0
  32. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/docs/guides/BENCHMARK_BIAS_REVIEW.md +1 -1
  33. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/docs/guides/BENCHMARK_METHODOLOGY.md +7 -4
  34. sqlguard_ninja-0.3.0/docs/guides/POLICY_AS_CODE.md +97 -0
  35. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/docs/guides/POLICY_REFERENCE.md +5 -0
  36. sqlguard_ninja-0.3.0/docs/releases/v0.2.0.md +27 -0
  37. sqlguard_ninja-0.3.0/docs/releases/v0.3.0.md +29 -0
  38. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/docs/security/THREAT_MODEL.md +2 -0
  39. sqlguard_ninja-0.3.0/src/sqlguard_ninja/_version.py +1 -0
  40. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/benchmarking/compare.py +8 -1
  41. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/benchmarking/dataset.py +38 -2
  42. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/benchmarking/metrics.py +66 -2
  43. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/benchmarking/runner.py +35 -0
  44. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/cli/config.py +2 -0
  45. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/cli/main.py +162 -6
  46. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/core/analysis.py +9 -1
  47. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/core/findings.py +4 -0
  48. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/core/guard.py +4 -0
  49. sqlguard_ninja-0.3.0/src/sqlguard_ninja/core/lineage.py +199 -0
  50. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/core/rules/tenant.py +56 -25
  51. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/integrations/audit.py +8 -0
  52. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/integrations/checkpoint.py +37 -4
  53. sqlguard_ninja-0.3.0/src/sqlguard_ninja/policy/inheritance.py +118 -0
  54. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/policy/model.py +47 -3
  55. sqlguard_ninja-0.3.0/src/sqlguard_ninja/policy/templates/analytics_readonly.yaml +31 -0
  56. sqlguard_ninja-0.3.0/src/sqlguard_ninja/policy/templates/minimal.yaml +17 -0
  57. sqlguard_ninja-0.3.0/src/sqlguard_ninja/policy/templates/multi_tenant_saas.yaml +53 -0
  58. sqlguard_ninja-0.3.0/src/sqlguard_ninja/policy/tools.py +410 -0
  59. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/privacy/rules.py +53 -14
  60. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/reporting/markdown.py +36 -5
  61. sqlguard_ninja-0.3.0/src/sqlguard_ninja/tenancy.py +160 -0
  62. sqlguard_ninja-0.3.0/tests/security/test_tenant_rewrite.py +116 -0
  63. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/tests/unit/test_benchmark_engine.py +77 -0
  64. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/tests/unit/test_cli.py +47 -0
  65. sqlguard_ninja-0.3.0/tests/unit/test_lineage.py +84 -0
  66. sqlguard_ninja-0.3.0/tests/unit/test_policy_inheritance.py +162 -0
  67. sqlguard_ninja-0.3.0/tests/unit/test_policy_tools.py +254 -0
  68. sqlguard_ninja-0.1.1/src/sqlguard_ninja/_version.py +0 -1
  69. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/.gitignore +0 -0
  70. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/LICENSE +0 -0
  71. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/THIRD_PARTY_NOTICES.md +0 -0
  72. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/benchmarks/datasets/external/README.md +0 -0
  73. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/benchmarks/datasets/v1/cases/01_destructive.yaml +0 -0
  74. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/benchmarks/datasets/v1/cases/02_multi_statement_and_formatting.yaml +0 -0
  75. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/benchmarks/datasets/v1/cases/03_table_and_column_access.yaml +0 -0
  76. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/benchmarks/datasets/v1/cases/06_cte_nested_unicode.yaml +0 -0
  77. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/benchmarks/datasets/v1/cases/07_legitimate_lookalike_cost_dialect.yaml +0 -0
  78. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/benchmarks/datasets/v1/generated/grant_matrix.yaml +0 -0
  79. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/benchmarks/datasets/v1/generated/label_matrix.yaml +0 -0
  80. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/benchmarks/datasets/v1/generated/tenant_matrix.yaml +0 -0
  81. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/benchmarks/datasets/v1/generated/transforms.yaml +0 -0
  82. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/benchmarks/policies/retail_saas.yaml +0 -0
  83. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/benchmarks/results/v1.0.0/agent-sql-guard.json +0 -0
  84. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/benchmarks/results/v1.0.0/agent-sql-guard.md +0 -0
  85. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/benchmarks/results/v1.0.0/krish2105-sqlguard.json +0 -0
  86. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/benchmarks/results/v1.0.0/krish2105-sqlguard.md +0 -0
  87. {sqlguard_ninja-0.1.1/benchmarks/baselines → sqlguard_ninja-0.3.0/benchmarks/results/v1.0.0}/native.json +0 -0
  88. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/benchmarks/results/v1.0.0/native.md +0 -0
  89. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/benchmarks/results/v1.0.0/sql-guardrail.json +0 -0
  90. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/benchmarks/results/v1.0.0/sql-guardrail.md +0 -0
  91. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/docs/benchmarks/RESULTS_v1.md +0 -0
  92. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/docs/guides/CI_INTEGRATION.md +0 -0
  93. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/docs/guides/QUERY_COST.md +0 -0
  94. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/docs/release/FINAL_TECHNICAL_AUDIT.md +0 -0
  95. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/docs/releases/v0.1.0.md +0 -0
  96. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/docs/releases/v0.1.1.md +0 -0
  97. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/docs/research/COMPETITIVE_ANALYSIS.md +0 -0
  98. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/docs/security/STATIC_ANALYSIS_LIMITS.md +0 -0
  99. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/examples/_shared.py +0 -0
  100. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/examples/fastapi/app.py +0 -0
  101. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/examples/github-actions/sql-security.yml +0 -0
  102. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/examples/langchain/guarded_tool_demo.py +0 -0
  103. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/examples/langgraph/real_llm_agent.py +0 -0
  104. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/examples/langgraph/sql_agent_demo.py +0 -0
  105. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/examples/postgresql/plan_inspection_demo.py +0 -0
  106. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/examples/sdk/quickstart.py +0 -0
  107. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/examples/sqlite/text_to_sql_demo.py +0 -0
  108. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/pyproject.toml +0 -0
  109. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/__init__.py +0 -0
  110. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/benchmarking/__init__.py +0 -0
  111. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/benchmarking/adapters.py +0 -0
  112. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/benchmarking/builtin.py +0 -0
  113. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/benchmarking/fixtures.py +0 -0
  114. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/benchmarking/translate.py +0 -0
  115. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/benchmarking/workers/_protocol.py +0 -0
  116. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/benchmarking/workers/agent_sql_guard_worker.py +0 -0
  117. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/benchmarking/workers/krish_sqlguard_worker.py +0 -0
  118. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/benchmarking/workers/sql_guardrail_worker.py +0 -0
  119. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/cli/__init__.py +0 -0
  120. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/cli/templates.py +0 -0
  121. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/core/__init__.py +0 -0
  122. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/core/rules/__init__.py +0 -0
  123. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/core/rules/access.py +0 -0
  124. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/core/rules/base.py +0 -0
  125. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/core/rules/catalog.py +0 -0
  126. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/core/rules/functions.py +0 -0
  127. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/core/rules/statements.py +0 -0
  128. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/core/rules/structure.py +0 -0
  129. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/integrations/__init__.py +0 -0
  130. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/integrations/executors.py +0 -0
  131. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/integrations/fastapi.py +0 -0
  132. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/integrations/langchain.py +0 -0
  133. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/integrations/langgraph.py +0 -0
  134. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/policy/__init__.py +0 -0
  135. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/privacy/__init__.py +0 -0
  136. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/privacy/suggest.py +0 -0
  137. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/py.typed +0 -0
  138. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/query_cost/__init__.py +0 -0
  139. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/query_cost/postgres.py +0 -0
  140. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/query_cost/static.py +0 -0
  141. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/src/sqlguard_ninja/reporting/__init__.py +0 -0
  142. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/tests/__init__.py +0 -0
  143. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/tests/conftest.py +0 -0
  144. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/tests/integration/__init__.py +0 -0
  145. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/tests/integration/test_corpus_sqlite_validation.py +0 -0
  146. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/tests/integration/test_external_adapters.py +0 -0
  147. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/tests/integration/test_frameworks.py +0 -0
  148. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/tests/integration/test_postgres.py +0 -0
  149. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/tests/pg_support.py +0 -0
  150. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/tests/property/__init__.py +0 -0
  151. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/tests/property/test_guard_properties.py +0 -0
  152. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/tests/security/__init__.py +0 -0
  153. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/tests/security/test_agent_boundaries.py +0 -0
  154. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/tests/security/test_corpus_native.py +0 -0
  155. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/tests/unit/__init__.py +0 -0
  156. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/tests/unit/helpers.py +0 -0
  157. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/tests/unit/test_dataset.py +0 -0
  158. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/tests/unit/test_docs.py +0 -0
  159. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/tests/unit/test_function_policy_mechanics.py +0 -0
  160. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/tests/unit/test_policy.py +0 -0
  161. {sqlguard_ninja-0.1.1 → sqlguard_ninja-0.3.0}/tests/unit/test_rules.py +0 -0
@@ -3,6 +3,51 @@
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.3.0] — 2026-10-24
7
+
8
+ ### Added
9
+ * **Role inheritance** (`extends`): grants merge, explicit denies are sticky, and conflicts,
10
+ unknown parents and cycles are load errors.
11
+ * **Policy metadata and identity:** `metadata.revision/owner/change_ticket`, a policy
12
+ fingerprint, and a per-decision `decision_id`. Audit events add `policy_revision`,
13
+ `policy_fingerprint`, `decision_id`, `correlation_id`, a literal-insensitive
14
+ `query_fingerprint`, and `tenant_filter_rewrite`.
15
+ * **Policy CLI:** `policy template`, `policy diff` (effect classification,
16
+ `--fail-on-relaxation`), `policy simulate` (`--against`, `--fail-on-change`),
17
+ `policy explain` (decision or column access, with inheritance source).
18
+ * **Templates:** `minimal`, `multi_tenant_saas`, `analytics_readonly`.
19
+ * **Opt-in AST tenant-filter rewrite** (`sqlguard_ninja.tenancy`,
20
+ `SQLCheckpoint(rewrite_tenant_filters=True)`) with re-validation and refusal rules (ADR-011).
21
+ * Docs: `docs/guides/POLICY_AS_CODE.md`; ADR-011, ADR-012; threat model T6a/T6b.
22
+
23
+ ### Compatibility
24
+ * Policy files without the new fields behave exactly as before. `ValidationResult` gains
25
+ fields with defaults.
26
+
27
+ ## [0.2.0] — 2026-10-24
28
+
29
+ ### Added
30
+ * **Lineage-aware privacy** (`core/lineage.py`). An `aggregate_only` column projected raw in a
31
+ CTE or derived table is accepted only when every downstream consumer aggregates it
32
+ statistically. Whole-row use, filters, ordering, windows, MIN/MAX and a raw use by any
33
+ consumer stay denied (issue #8).
34
+ * **Tenant push-down.** An outer tenant pin on an unmodified projection of the tenant column
35
+ satisfies the inner read when the inner scope has no aggregation, window, LIMIT, OFFSET or
36
+ FETCH and every consumer pins it, recursively (issue #9).
37
+ * The small-cohort check follows identifiers through CTEs and derived tables, so the lineage
38
+ relaxation cannot bypass it (found by new boundary case LIN-012).
39
+ * Privacy findings carry structured lineage metadata (base column, JSON path, scope, labels).
40
+ * Benchmark: `internal` / `independent` dataset tiers, flag basis (policy vs unsupported SQL),
41
+ F1, 95% Wilson intervals, throughput, CSV output (`--csv`), per-file SHA-256 dataset hashes
42
+ in results and `sqlninja dataset stats`.
43
+ * Approved-relabel workflow: `LABEL_CHANGES.yaml` (CODEOWNERS-protected) lists reviewed label
44
+ changes; `benchmark compare --approved-label-changes` / `ci.approved_label_changes`.
45
+ * Corpus 1.1.0: 21 lineage boundary cases; 2 approved relabels (PRV-026, TEN-021).
46
+
47
+ ### Changed
48
+ * Decisions changed for exactly two corpus cases (PRV-026, TEN-021: deny → allow); all other
49
+ 1,042 evaluations are unchanged.
50
+
6
51
  ## [0.1.1] — 2026-10-24
7
52
 
8
53
  Documentation and governance patch. No changes to policy decisions.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: sqlguard-ninja
3
- Version: 0.1.1
3
+ Version: 0.3.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
@@ -70,7 +70,7 @@ the *authenticated* caller: which tables and columns a role may use, which data
70
70
  appear only in aggregates or only after human approval, and which tenant the caller belongs
71
71
  to. It records an audit trail and gives the agent an explanation it can act on.
72
72
 
73
- It ships with a labelled benchmark corpus (530 cases, 1,002 dialect evaluations) and a
73
+ It ships with a labelled benchmark corpus (551 cases, 1,044 dialect evaluations) and a
74
74
  regression gate for CI. The same benchmark harness can evaluate other open-source guards
75
75
  side by side.
76
76
 
@@ -83,9 +83,9 @@ side by side.
83
83
  | Workstream | What you get | Status |
84
84
  |---|---|---|
85
85
  | **Policy engine** | Read-only enforcement, table/column grants, tenant isolation, function and catalog rules, structural limits. Built on [sqlglot](https://github.com/tobymao/sqlglot). Fails closed when analysis is incomplete. | PostgreSQL + SQLite tested |
86
- | **Privacy pack** | Explicit classification labels, `deny` / `aggregate_only` / `review` per role, JSON-path labels, small-cohort review, minimisation hints and alternatives | implemented |
86
+ | **Privacy pack** | Explicit classification labels, `deny` / `aggregate_only` / `review` per role, JSON-path labels, lineage through CTEs and derived tables, small-cohort review, minimisation hints and alternatives | implemented |
87
87
  | **Agent integrations** | `SQLCheckpoint` with block / review / audit modes, hash-bound single-use approvals, retry lock-out, redacted audit events. LangChain tool, LangGraph nodes, FastAPI router | implemented |
88
- | **Benchmark engine** | Versioned corpus, metrics (recall, precision, FPR, FNR, exact match, per category/dialect, latency percentiles), adapters for native, callable and isolated external validators, JSON and Markdown reports | implemented |
88
+ | **Benchmark engine** | Versioned corpus with per-file SHA-256 hashes, internal and independent tiers, metrics (recall, precision, F1, FPR, FNR with 95% Wilson intervals, exact match, throughput, latency percentiles, per category/dialect/tier), adapters for native, callable and isolated external validators, JSON, CSV and Markdown reports | implemented |
89
89
  | **Query cost** | Explainable static score; optional PostgreSQL `EXPLAIN (FORMAT JSON)` inspection, gated and read-only | implemented |
90
90
  | **CI** | Composite GitHub Action and CLI gate: security, usability, label-change and error regressions against an approved baseline | implemented |
91
91
 
@@ -246,6 +246,23 @@ Labels also apply to paths inside JSON columns (`profile->'health'->>'allergies'
246
246
  suggestions are never enforced. This is a technical control, not a certification of GDPR
247
247
  compliance. Full semantics: [POLICY_REFERENCE.md](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/POLICY_REFERENCE.md).
248
248
 
249
+ ## Policy as code
250
+
251
+ Roles can inherit (`extends`), and explicit denies cannot be relaxed by a child. Every decision
252
+ carries the policy revision, the policy fingerprint and a decision id. Review changes before
253
+ activating them:
254
+
255
+ ```bash
256
+ sqlninja policy template multi_tenant_saas --output policy.yaml
257
+ sqlninja policy diff old.yaml policy.yaml --fail-on-relaxation
258
+ sqlninja policy simulate --policy old.yaml --against policy.yaml --cases cases.yaml
259
+ sqlninja policy explain --policy policy.yaml --role support --column customers.email
260
+ ```
261
+
262
+ Optional: `SQLCheckpoint(..., rewrite_tenant_filters=True)` adds missing tenant filters
263
+ through the AST and executes only the re-validated rewrite. See
264
+ [POLICY_AS_CODE.md](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/POLICY_AS_CODE.md).
265
+
249
266
  ## Query cost analysis
250
267
 
251
268
  Every validation includes an explainable static score that uses the catalog's
@@ -279,22 +296,24 @@ sqlninja benchmark run --dataset builtin:v1 --adapter external:sql-guardrail
279
296
  sqlninja benchmark compare --baseline benchmarks/baselines/native.json --candidate results/latest.json
280
297
  ```
281
298
 
282
- Results for corpus v1.0.0 (Windows 11, Python 3.11, 1,002 evaluations). Details and raw files:
283
- [RESULTS_v1.md](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/benchmarks/RESULTS_v1.md).
284
-
285
- | Validator | Recall | Precision | FPR | Recall / FPR within declared capability | p95 ms |
286
- |---|---:|---:|---:|---:|---:|
287
- | SQLGuard Ninja 0.1.0 | 100.0% | 100.0% | 0.0% | 100.0% / 0.0% | 2.15 |
288
- | sql-guardrail 0.5.2 | 98.6% | 86.6% | 21.2% | 98.3% / 19.3% | 1.72 |
289
- | agent-sql-guard 0.2.0 | 67.9% | 86.6% | 14.5% | 89.5% / 17.2% | 1.26 |
290
- | krish2105/sqlguard 0.1.0 | 65.8% | 91.4% | 8.6% | 83.5% / 5.2% | 1.22 |
291
-
292
- **Read the native row with care.** The corpus and the engine were developed together, and
293
- every disagreement was triaged by fixing the engine or correcting a label (both are logged).
294
- 100% shows consistency with the documented semantics, not independent detection quality. The
295
- other tools have smaller policy models (no roles, labels, aggregate-only access or review), so
296
- the "within capability" column is the fairer comparison. Methodology and threats to validity:
297
- [BENCHMARK_METHODOLOGY.md](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/BENCHMARK_METHODOLOGY.md).
299
+ Results for corpus v1.1.0 (551 cases, 1,044 evaluations; SQLGuard Ninja 0.2.0; Windows 11,
300
+ 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).
302
+
303
+ | Validator | Recall (95% CI) | Precision | F1 | FPR (95% CI) | Recall / FPR within declared capability | p95 ms |
304
+ |---|---:|---:|---:|---:|---:|---:|
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 |
309
+
310
+ **All of these are internal results.** The corpus was written by this project, alongside the
311
+ engine. The native 100% shows consistency with the documented semantics, not independent
312
+ detection quality. No independently sourced dataset exists yet ([intake rules](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/benchmarks/datasets/external/README.md),
313
+ issue #6). Reports keep `internal` and `independent` tiers separate, and they also separate
314
+ policy denials from unsupported-SQL denials. Methodology and bias review:
315
+ [BENCHMARK_METHODOLOGY.md](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/BENCHMARK_METHODOLOGY.md),
316
+ [BENCHMARK_BIAS_REVIEW.md](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/BENCHMARK_BIAS_REVIEW.md).
298
317
 
299
318
  ## How it relates to existing tools
300
319
 
@@ -338,6 +357,7 @@ writes, more tested dialects, and SARIF output. Details in [ROADMAP.md](https://
338
357
  ## Documentation
339
358
 
340
359
  * [Policy reference](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/POLICY_REFERENCE.md)
360
+ * [Policy as code](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/POLICY_AS_CODE.md)
341
361
  * [Agent integration](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/AGENT_INTEGRATION.md)
342
362
  * [Query cost](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/QUERY_COST.md)
343
363
  * [CI integration](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/CI_INTEGRATION.md)
@@ -14,7 +14,7 @@ the *authenticated* caller: which tables and columns a role may use, which data
14
14
  appear only in aggregates or only after human approval, and which tenant the caller belongs
15
15
  to. It records an audit trail and gives the agent an explanation it can act on.
16
16
 
17
- It ships with a labelled benchmark corpus (530 cases, 1,002 dialect evaluations) and a
17
+ It ships with a labelled benchmark corpus (551 cases, 1,044 dialect evaluations) and a
18
18
  regression gate for CI. The same benchmark harness can evaluate other open-source guards
19
19
  side by side.
20
20
 
@@ -27,9 +27,9 @@ side by side.
27
27
  | Workstream | What you get | Status |
28
28
  |---|---|---|
29
29
  | **Policy engine** | Read-only enforcement, table/column grants, tenant isolation, function and catalog rules, structural limits. Built on [sqlglot](https://github.com/tobymao/sqlglot). Fails closed when analysis is incomplete. | PostgreSQL + SQLite tested |
30
- | **Privacy pack** | Explicit classification labels, `deny` / `aggregate_only` / `review` per role, JSON-path labels, small-cohort review, minimisation hints and alternatives | implemented |
30
+ | **Privacy pack** | Explicit classification labels, `deny` / `aggregate_only` / `review` per role, JSON-path labels, lineage through CTEs and derived tables, small-cohort review, minimisation hints and alternatives | implemented |
31
31
  | **Agent integrations** | `SQLCheckpoint` with block / review / audit modes, hash-bound single-use approvals, retry lock-out, redacted audit events. LangChain tool, LangGraph nodes, FastAPI router | implemented |
32
- | **Benchmark engine** | Versioned corpus, metrics (recall, precision, FPR, FNR, exact match, per category/dialect, latency percentiles), adapters for native, callable and isolated external validators, JSON and Markdown reports | implemented |
32
+ | **Benchmark engine** | Versioned corpus with per-file SHA-256 hashes, internal and independent tiers, metrics (recall, precision, F1, FPR, FNR with 95% Wilson intervals, exact match, throughput, latency percentiles, per category/dialect/tier), adapters for native, callable and isolated external validators, JSON, CSV and Markdown reports | implemented |
33
33
  | **Query cost** | Explainable static score; optional PostgreSQL `EXPLAIN (FORMAT JSON)` inspection, gated and read-only | implemented |
34
34
  | **CI** | Composite GitHub Action and CLI gate: security, usability, label-change and error regressions against an approved baseline | implemented |
35
35
 
@@ -190,6 +190,23 @@ Labels also apply to paths inside JSON columns (`profile->'health'->>'allergies'
190
190
  suggestions are never enforced. This is a technical control, not a certification of GDPR
191
191
  compliance. Full semantics: [POLICY_REFERENCE.md](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/POLICY_REFERENCE.md).
192
192
 
193
+ ## Policy as code
194
+
195
+ Roles can inherit (`extends`), and explicit denies cannot be relaxed by a child. Every decision
196
+ carries the policy revision, the policy fingerprint and a decision id. Review changes before
197
+ activating them:
198
+
199
+ ```bash
200
+ sqlninja policy template multi_tenant_saas --output policy.yaml
201
+ sqlninja policy diff old.yaml policy.yaml --fail-on-relaxation
202
+ sqlninja policy simulate --policy old.yaml --against policy.yaml --cases cases.yaml
203
+ sqlninja policy explain --policy policy.yaml --role support --column customers.email
204
+ ```
205
+
206
+ Optional: `SQLCheckpoint(..., rewrite_tenant_filters=True)` adds missing tenant filters
207
+ through the AST and executes only the re-validated rewrite. See
208
+ [POLICY_AS_CODE.md](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/POLICY_AS_CODE.md).
209
+
193
210
  ## Query cost analysis
194
211
 
195
212
  Every validation includes an explainable static score that uses the catalog's
@@ -223,22 +240,24 @@ sqlninja benchmark run --dataset builtin:v1 --adapter external:sql-guardrail
223
240
  sqlninja benchmark compare --baseline benchmarks/baselines/native.json --candidate results/latest.json
224
241
  ```
225
242
 
226
- Results for corpus v1.0.0 (Windows 11, Python 3.11, 1,002 evaluations). Details and raw files:
227
- [RESULTS_v1.md](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/benchmarks/RESULTS_v1.md).
228
-
229
- | Validator | Recall | Precision | FPR | Recall / FPR within declared capability | p95 ms |
230
- |---|---:|---:|---:|---:|---:|
231
- | SQLGuard Ninja 0.1.0 | 100.0% | 100.0% | 0.0% | 100.0% / 0.0% | 2.15 |
232
- | sql-guardrail 0.5.2 | 98.6% | 86.6% | 21.2% | 98.3% / 19.3% | 1.72 |
233
- | agent-sql-guard 0.2.0 | 67.9% | 86.6% | 14.5% | 89.5% / 17.2% | 1.26 |
234
- | krish2105/sqlguard 0.1.0 | 65.8% | 91.4% | 8.6% | 83.5% / 5.2% | 1.22 |
235
-
236
- **Read the native row with care.** The corpus and the engine were developed together, and
237
- every disagreement was triaged by fixing the engine or correcting a label (both are logged).
238
- 100% shows consistency with the documented semantics, not independent detection quality. The
239
- other tools have smaller policy models (no roles, labels, aggregate-only access or review), so
240
- the "within capability" column is the fairer comparison. Methodology and threats to validity:
241
- [BENCHMARK_METHODOLOGY.md](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/BENCHMARK_METHODOLOGY.md).
243
+ Results for corpus v1.1.0 (551 cases, 1,044 evaluations; SQLGuard Ninja 0.2.0; Windows 11,
244
+ 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).
246
+
247
+ | Validator | Recall (95% CI) | Precision | F1 | FPR (95% CI) | Recall / FPR within declared capability | p95 ms |
248
+ |---|---:|---:|---:|---:|---:|---:|
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 |
253
+
254
+ **All of these are internal results.** The corpus was written by this project, alongside the
255
+ engine. The native 100% shows consistency with the documented semantics, not independent
256
+ detection quality. No independently sourced dataset exists yet ([intake rules](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/benchmarks/datasets/external/README.md),
257
+ issue #6). Reports keep `internal` and `independent` tiers separate, and they also separate
258
+ policy denials from unsupported-SQL denials. Methodology and bias review:
259
+ [BENCHMARK_METHODOLOGY.md](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/BENCHMARK_METHODOLOGY.md),
260
+ [BENCHMARK_BIAS_REVIEW.md](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/BENCHMARK_BIAS_REVIEW.md).
242
261
 
243
262
  ## How it relates to existing tools
244
263
 
@@ -282,6 +301,7 @@ writes, more tested dialects, and SARIF output. Details in [ROADMAP.md](https://
282
301
  ## Documentation
283
302
 
284
303
  * [Policy reference](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/POLICY_REFERENCE.md)
304
+ * [Policy as code](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/POLICY_AS_CODE.md)
285
305
  * [Agent integration](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/AGENT_INTEGRATION.md)
286
306
  * [Query cost](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/QUERY_COST.md)
287
307
  * [CI integration](https://github.com/Pratik653/SQLGuard_Ninjapy/blob/main/docs/guides/CI_INTEGRATION.md)