sqlproof 0.1.0a1__tar.gz → 0.2.2__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 (135) hide show
  1. sqlproof-0.2.2/.github/ISSUE_TEMPLATE/bug_report.yml +79 -0
  2. sqlproof-0.2.2/.github/ISSUE_TEMPLATE/config.yml +5 -0
  3. sqlproof-0.2.2/.github/ISSUE_TEMPLATE/feature_request.yml +43 -0
  4. sqlproof-0.2.2/.github/ISSUE_TEMPLATE/question.yml +28 -0
  5. sqlproof-0.2.2/.github/PULL_REQUEST_TEMPLATE.md +43 -0
  6. sqlproof-0.2.2/.github/actions/setup-supabase-test-db/action.yml +42 -0
  7. sqlproof-0.2.2/.github/actions/setup-supabase-test-db/sql/supabase-test-init.sql +52 -0
  8. sqlproof-0.2.2/.github/dependabot.yml +45 -0
  9. sqlproof-0.2.2/.github/workflows/ci.yml +73 -0
  10. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/.github/workflows/deploy-website.yml +6 -0
  11. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/.github/workflows/nightly.yml +1 -1
  12. sqlproof-0.2.2/.github/workflows/pr-title.yml +42 -0
  13. sqlproof-0.2.2/.github/workflows/release-please.yml +33 -0
  14. sqlproof-0.2.2/.github/workflows/release.yml +71 -0
  15. sqlproof-0.2.2/.github/workflows/uv-lock-refresh.yml +45 -0
  16. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/.gitignore +2 -0
  17. sqlproof-0.2.2/.release-please-manifest.json +3 -0
  18. sqlproof-0.2.2/.sqlproof/failures/property_fails.json +24 -0
  19. sqlproof-0.2.2/AGENTS.md +465 -0
  20. sqlproof-0.2.2/CHANGELOG.md +162 -0
  21. sqlproof-0.2.2/CONTRIBUTING.md +230 -0
  22. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/PKG-INFO +61 -13
  23. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/README.md +59 -11
  24. sqlproof-0.2.2/SECURITY.md +60 -0
  25. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/SPEC.md +52 -7
  26. sqlproof-0.2.2/docs/superpowers/specs/2026-05-30-release-engineering-design.md +368 -0
  27. sqlproof-0.2.2/examples/supabase_rls/README.md +121 -0
  28. sqlproof-0.2.2/examples/supabase_rls/schema.sql +100 -0
  29. sqlproof-0.2.2/examples/supabase_rls/test_rls.pgtap.sql +177 -0
  30. sqlproof-0.2.2/examples/supabase_rls/test_rls.py +284 -0
  31. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/pyproject.toml +2 -10
  32. sqlproof-0.2.2/release-please-config.json +30 -0
  33. sqlproof-0.2.2/src/sqlproof/_version.py +1 -0
  34. sqlproof-0.2.2/src/sqlproof/contrib/plpgsql_coverage.py +494 -0
  35. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/contrib/supabase.py +78 -10
  36. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/core.py +9 -6
  37. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/generators/columns.py +4 -2
  38. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/generators/graph.py +2 -0
  39. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/generators/rows.py +7 -2
  40. sqlproof-0.2.2/src/sqlproof/pytest_plugin.py +289 -0
  41. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/runners/property.py +30 -6
  42. sqlproof-0.2.2/tests/integration/test_plpgsql_coverage.py +204 -0
  43. sqlproof-0.2.2/tests/integration/test_pytest_plugin_fixtures_integration.py +89 -0
  44. sqlproof-0.2.2/tests/integration/test_supabase_auth_surface.py +110 -0
  45. sqlproof-0.2.2/tests/unit/test_column_strategies.py +217 -0
  46. sqlproof-0.2.2/tests/unit/test_constraint_strategies.py +317 -0
  47. sqlproof-0.2.2/tests/unit/test_contrib_plpgsql_coverage.py +489 -0
  48. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/tests/unit/test_contrib_supabase.py +114 -0
  49. sqlproof-0.2.2/tests/unit/test_parse_sql_edge_cases.py +78 -0
  50. sqlproof-0.2.2/tests/unit/test_pytest_plugin_fixtures.py +144 -0
  51. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/tests/unit/test_runner_slice.py +164 -1
  52. sqlproof-0.2.2/tests/unit/test_well_known.py +126 -0
  53. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/uv.lock +1 -1
  54. sqlproof-0.2.2/website/.env.example +12 -0
  55. sqlproof-0.2.2/website/astro.config.mjs +71 -0
  56. sqlproof-0.2.2/website/src/content/docs/examples/data-generation.md +309 -0
  57. sqlproof-0.2.2/website/src/content/docs/examples/property-patterns.md +234 -0
  58. sqlproof-0.2.2/website/src/content/docs/examples/testing-sql-functions.md +400 -0
  59. sqlproof-0.2.2/website/src/content/docs/guides/ci-cd.md +181 -0
  60. sqlproof-0.2.2/website/src/content/docs/guides/vs-pgtap.md +187 -0
  61. sqlproof-0.2.2/website/src/content/docs/supabase-quickstart.md +214 -0
  62. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/website/src/pages/index.astro +12 -6
  63. sqlproof-0.2.2/website/src/posthog.mjs +41 -0
  64. sqlproof-0.1.0a1/.github/workflows/ci.yml +0 -38
  65. sqlproof-0.1.0a1/.github/workflows/release.yml +0 -36
  66. sqlproof-0.1.0a1/CHANGELOG.md +0 -58
  67. sqlproof-0.1.0a1/src/sqlproof/_version.py +0 -1
  68. sqlproof-0.1.0a1/src/sqlproof/pytest_plugin.py +0 -24
  69. sqlproof-0.1.0a1/website/astro.config.mjs +0 -42
  70. sqlproof-0.1.0a1/website/src/content/docs/guides/ci-cd.md +0 -67
  71. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/examples/ecommerce/schema.sql +0 -0
  72. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/examples/ecommerce/test_orders.py +0 -0
  73. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/examples/ripenn_scoring/schema.sql +0 -0
  74. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/examples/ripenn_scoring/test_scoring.py +0 -0
  75. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/__init__.py +0 -0
  76. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/cli.py +0 -0
  77. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/client.py +0 -0
  78. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/config.py +0 -0
  79. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/contrib/__init__.py +0 -0
  80. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/coverage/__init__.py +0 -0
  81. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/coverage/diversity.py +0 -0
  82. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/coverage/plpgsql.py +0 -0
  83. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/coverage/schema_shape.py +0 -0
  84. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/exceptions.py +0 -0
  85. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/generators/__init__.py +0 -0
  86. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/generators/constraints.py +0 -0
  87. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/generators/functions.py +0 -0
  88. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/generators/sampling.py +0 -0
  89. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/generators/well_known.py +0 -0
  90. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/reporter/__init__.py +0 -0
  91. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/reporter/console.py +0 -0
  92. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/reporter/json_io.py +0 -0
  93. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/runners/__init__.py +0 -0
  94. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/runners/db.py +0 -0
  95. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/runners/migration.py +0 -0
  96. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/runners/overload.py +0 -0
  97. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/runners/rls.py +0 -0
  98. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/runners/stateful.py +0 -0
  99. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/schema/__init__.py +0 -0
  100. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/schema/dependency_graph.py +0 -0
  101. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/schema/fingerprint.py +0 -0
  102. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/schema/introspect.py +0 -0
  103. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/schema/model.py +0 -0
  104. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/schema/parse_sql.py +0 -0
  105. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/testing.py +0 -0
  106. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/src/sqlproof/types.py +0 -0
  107. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/tests/benchmarks/test_generation_benchmark.py +0 -0
  108. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/tests/conftest.py +0 -0
  109. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/tests/integration/test_postgres_execution.py +0 -0
  110. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/tests/meta/test_meta_properties.py +0 -0
  111. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/tests/unit/test_cli_smoke.py +0 -0
  112. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/tests/unit/test_db_manager.py +0 -0
  113. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/tests/unit/test_generators_core.py +0 -0
  114. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/tests/unit/test_package_scaffold.py +0 -0
  115. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/tests/unit/test_schema_core.py +0 -0
  116. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/tests/unit/test_state_machine.py +0 -0
  117. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/tests/unit/test_v01_surfaces.py +0 -0
  118. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/website/package-lock.json +0 -0
  119. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/website/package.json +0 -0
  120. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/website/public/CNAME +0 -0
  121. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/website/public/favicon.svg +0 -0
  122. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/website/src/content/config.ts +0 -0
  123. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/website/src/content/docs/api/check-options.md +0 -0
  124. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/website/src/content/docs/api/sqlproof-class.md +0 -0
  125. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/website/src/content/docs/api/state-machine.md +0 -0
  126. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/website/src/content/docs/api/table-customization.md +0 -0
  127. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/website/src/content/docs/examples/orders.md +0 -0
  128. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/website/src/content/docs/getting-started.md +0 -0
  129. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/website/src/content/docs/guides/custom-generators.md +0 -0
  130. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/website/src/content/docs/guides/fk-distributions.md +0 -0
  131. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/website/src/content/docs/guides/local-dev.md +0 -0
  132. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/website/src/content/docs/guides/security.md +0 -0
  133. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/website/src/content/docs/guides/supabase.md +0 -0
  134. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/website/src/styles/custom.css +0 -0
  135. {sqlproof-0.1.0a1 → sqlproof-0.2.2}/website/tsconfig.json +0 -0
@@ -0,0 +1,79 @@
1
+ name: Bug report
2
+ description: Something is broken or behaving unexpectedly.
3
+ title: "fix: <one-line summary>"
4
+ labels: ["bug"]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: |
9
+ Thanks for filing a bug. The clearer the repro, the faster we can fix it.
10
+
11
+ - type: textarea
12
+ id: summary
13
+ attributes:
14
+ label: Summary
15
+ description: One or two sentences on what's wrong.
16
+ placeholder: "`SqlProof.check()` raises X when the schema contains Y."
17
+ validations:
18
+ required: true
19
+
20
+ - type: textarea
21
+ id: reproduction
22
+ attributes:
23
+ label: Minimal reproduction
24
+ description: |
25
+ Smallest code/schema/dataset that triggers the bug. A self-contained
26
+ Python script we can paste and run is ideal.
27
+ render: python
28
+ validations:
29
+ required: true
30
+
31
+ - type: textarea
32
+ id: expected
33
+ attributes:
34
+ label: Expected behavior
35
+ placeholder: "Should have returned ... / shouldn't have raised."
36
+ validations:
37
+ required: true
38
+
39
+ - type: textarea
40
+ id: actual
41
+ attributes:
42
+ label: Actual behavior
43
+ description: Include the full traceback if applicable.
44
+ render: shell
45
+ validations:
46
+ required: true
47
+
48
+ - type: input
49
+ id: sqlproof-version
50
+ attributes:
51
+ label: sqlproof version
52
+ placeholder: "e.g. 0.1.0a1 (or `uv pip show sqlproof`)"
53
+ validations:
54
+ required: true
55
+
56
+ - type: input
57
+ id: python-version
58
+ attributes:
59
+ label: Python version
60
+ placeholder: "e.g. 3.12.2"
61
+ validations:
62
+ required: true
63
+
64
+ - type: input
65
+ id: postgres-version
66
+ attributes:
67
+ label: Postgres version
68
+ description: Output of `SELECT version();` against your test database. Skip if not DB-related.
69
+ placeholder: "e.g. PostgreSQL 15.8 (Supabase)"
70
+ validations:
71
+ required: false
72
+
73
+ - type: textarea
74
+ id: additional
75
+ attributes:
76
+ label: Additional context
77
+ description: Anything else that might help — workarounds you tried, related issues, screenshots.
78
+ validations:
79
+ required: false
@@ -0,0 +1,5 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Security vulnerability
4
+ url: https://github.com/alialavia/sqlproof/security/advisories/new
5
+ about: Please report security issues privately via GitHub Security Advisories. See SECURITY.md.
@@ -0,0 +1,43 @@
1
+ name: Feature request
2
+ description: Propose a new feature or capability.
3
+ title: "feat: <one-line summary>"
4
+ labels: ["enhancement"]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: |
9
+ Thanks for the suggestion. Helping us understand the *problem* you're
10
+ solving is more useful than a fully-specified solution — we may have
11
+ ideas you haven't considered.
12
+
13
+ - type: textarea
14
+ id: problem
15
+ attributes:
16
+ label: Problem
17
+ description: What are you trying to do that sqlproof doesn't currently let you do well? Include a concrete use case.
18
+ validations:
19
+ required: true
20
+
21
+ - type: textarea
22
+ id: proposed
23
+ attributes:
24
+ label: Proposed solution
25
+ description: What you have in mind. Rough is fine — API sketch, behavior description, prior art elsewhere.
26
+ validations:
27
+ required: true
28
+
29
+ - type: textarea
30
+ id: alternatives
31
+ attributes:
32
+ label: Alternatives considered
33
+ description: What workarounds have you tried? Why aren't they good enough?
34
+ validations:
35
+ required: false
36
+
37
+ - type: textarea
38
+ id: additional
39
+ attributes:
40
+ label: Additional context
41
+ description: Links, screenshots, references to other libraries that solve this well.
42
+ validations:
43
+ required: false
@@ -0,0 +1,28 @@
1
+ name: Question
2
+ description: Ask about how to do something with sqlproof.
3
+ title: "question: <one-line summary>"
4
+ labels: ["question"]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: |
9
+ Questions are welcome. Before filing, please skim the [README](https://github.com/alialavia/sqlproof#readme)
10
+ and the [examples directory](https://github.com/alialavia/sqlproof/tree/main/examples) — the answer
11
+ might already be there.
12
+
13
+ - type: textarea
14
+ id: question
15
+ attributes:
16
+ label: Your question
17
+ description: What are you trying to do? What have you tried so far?
18
+ validations:
19
+ required: true
20
+
21
+ - type: textarea
22
+ id: context
23
+ attributes:
24
+ label: Context
25
+ description: Code snippets, schema, your environment — whatever helps frame the question.
26
+ render: python
27
+ validations:
28
+ required: false
@@ -0,0 +1,43 @@
1
+ <!--
2
+ Thanks for the contribution! A few quick notes before you fill this in:
3
+
4
+ 1. The PR title must follow Conventional Commits (e.g. `feat(generator):`,
5
+ `fix(core):`, `docs(readme):`). CI will fail if it doesn't parse.
6
+ See CONTRIBUTING.md for the full list of accepted types.
7
+
8
+ 2. The PR title becomes the squash-merge commit message on main and is what
9
+ release-please uses to compute the next version + changelog entry. Make
10
+ it accurate and self-contained.
11
+
12
+ 3. Delete sections below that don't apply.
13
+ -->
14
+
15
+ ## Summary
16
+
17
+ <!-- What changed? Bullets are great. -->
18
+
19
+ -
20
+
21
+ ## Why
22
+
23
+ <!-- The motivation. What problem does this solve, or what user request does
24
+ it satisfy? Link to the issue if there is one. -->
25
+
26
+ ## Test plan
27
+
28
+ <!-- Checklist of what you ran/verified locally. Tick the boxes you've
29
+ completed; leave unticked the things you'd like a reviewer to verify. -->
30
+
31
+ - [ ] `uv run pytest` passes
32
+ - [ ] `uv run ruff check src/ tests/` clean
33
+ - [ ] `uv run pyright` clean
34
+ - [ ] `uv run mypy src/sqlproof/` clean
35
+ - [ ] (if integration-affecting) tested locally against `supabase/postgres:15.8.1.040`
36
+ - [ ] (if user-facing) updated docs / README / examples
37
+ - [ ] (if breaking) PR title includes `!` or body includes `BREAKING CHANGE:` footer
38
+
39
+ ## Related
40
+
41
+ <!-- Issues this closes, PRs this depends on, follow-ups filed. -->
42
+
43
+ - Closes #
@@ -0,0 +1,42 @@
1
+ name: 'Set up Supabase-shaped test database'
2
+ description: |
3
+ Apply SqlProof's Supabase test-init SQL to a running Postgres so a bare
4
+ `supabase/postgres` image matches managed Supabase semantics (plpgsql_check
5
+ extension, JSON-aware auth.uid/role/email/jwt). Call this AFTER your
6
+ service container's healthcheck passes and BEFORE running your tests.
7
+
8
+ inputs:
9
+ database-url:
10
+ description: |
11
+ PostgreSQL DSN to apply the migration against. Use the same value you
12
+ pass to your tests as SQLPROOF_DATABASE_URL.
13
+ required: true
14
+ verbose:
15
+ description: |
16
+ If "true", print the resulting extension list and auth surface to the
17
+ job log so you can see what's installed. Default "false".
18
+ required: false
19
+ default: 'false'
20
+
21
+ runs:
22
+ using: composite
23
+ steps:
24
+ - name: Apply Supabase test-init SQL
25
+ shell: bash
26
+ env:
27
+ DSN: ${{ inputs.database-url }}
28
+ run: |
29
+ # Resolve this action's own checkout path so the SQL file is found
30
+ # regardless of where the caller mounted things.
31
+ psql -v ON_ERROR_STOP=1 "$DSN" -f "${GITHUB_ACTION_PATH}/sql/supabase-test-init.sql"
32
+
33
+ - name: Print resulting Postgres surface
34
+ if: inputs.verbose == 'true'
35
+ shell: bash
36
+ env:
37
+ DSN: ${{ inputs.database-url }}
38
+ run: |
39
+ echo "=== installed extensions ==="
40
+ psql "$DSN" -c "SELECT extname, extversion FROM pg_extension ORDER BY extname;"
41
+ echo "=== auth schema functions ==="
42
+ psql "$DSN" -c "SELECT n.nspname || '.' || p.proname AS function FROM pg_proc p JOIN pg_namespace n ON n.oid = p.pronamespace WHERE n.nspname = 'auth' ORDER BY proname;"
@@ -0,0 +1,52 @@
1
+ -- Bring a bare `supabase/postgres` container into lockstep with managed
2
+ -- Supabase semantics, so SqlProof's RLS-aware helpers (auth.uid(),
3
+ -- auth.role(), as_rls_user) behave the same way they would in production.
4
+ --
5
+ -- This applies two things the bare image is missing:
6
+ --
7
+ -- 1. `plpgsql_check` extension. The binary ships with the image but isn't
8
+ -- installed in the default database. Needed by
9
+ -- sqlproof.contrib.plpgsql_coverage.
10
+ --
11
+ -- 2. GoTrue's `20220224000811_update_auth_functions` migration. The bare
12
+ -- image's `auth.uid()` only reads the legacy singular GUC
13
+ -- `request.jwt.claim.sub`. PostgREST 8+ (and SqlProof's
14
+ -- `as_rls_user` helper) write the modern JSON `request.jwt.claims`
15
+ -- GUC. Managed Supabase patches this at deploy time via GoTrue; we
16
+ -- apply the same migration here so the bare image matches.
17
+ --
18
+ -- Source: https://github.com/supabase/auth/blob/master/migrations/20220224000811_update_auth_functions.up.sql
19
+
20
+ CREATE EXTENSION IF NOT EXISTS plpgsql_check;
21
+
22
+ CREATE OR REPLACE FUNCTION auth.uid()
23
+ RETURNS uuid LANGUAGE sql STABLE AS $$
24
+ SELECT COALESCE(
25
+ NULLIF(current_setting('request.jwt.claim.sub', true), ''),
26
+ (NULLIF(current_setting('request.jwt.claims', true), '')::jsonb ->> 'sub')
27
+ )::uuid
28
+ $$;
29
+
30
+ CREATE OR REPLACE FUNCTION auth.role()
31
+ RETURNS text LANGUAGE sql STABLE AS $$
32
+ SELECT COALESCE(
33
+ NULLIF(current_setting('request.jwt.claim.role', true), ''),
34
+ (NULLIF(current_setting('request.jwt.claims', true), '')::jsonb ->> 'role')
35
+ )::text
36
+ $$;
37
+
38
+ CREATE OR REPLACE FUNCTION auth.email()
39
+ RETURNS text LANGUAGE sql STABLE AS $$
40
+ SELECT COALESCE(
41
+ NULLIF(current_setting('request.jwt.claim.email', true), ''),
42
+ (NULLIF(current_setting('request.jwt.claims', true), '')::jsonb ->> 'email')
43
+ )::text
44
+ $$;
45
+
46
+ CREATE OR REPLACE FUNCTION auth.jwt()
47
+ RETURNS jsonb LANGUAGE sql STABLE AS $$
48
+ SELECT COALESCE(
49
+ NULLIF(current_setting('request.jwt.claim', true), ''),
50
+ NULLIF(current_setting('request.jwt.claims', true), '')
51
+ )::jsonb
52
+ $$;
@@ -0,0 +1,45 @@
1
+ version: 2
2
+ updates:
3
+ # Python runtime + dev dependencies declared in pyproject.toml.
4
+ # Dependabot bumps declared versions; uv-lock-refresh.yml regenerates
5
+ # uv.lock on each dependabot PR.
6
+ - package-ecosystem: pip
7
+ directory: "/"
8
+ schedule:
9
+ interval: weekly
10
+ day: monday
11
+ open-pull-requests-limit: 5
12
+ labels:
13
+ - dependencies
14
+ - python
15
+ commit-message:
16
+ prefix: chore
17
+ include: scope
18
+
19
+ # GitHub Actions versions (actions/checkout@vN, etc.)
20
+ - package-ecosystem: github-actions
21
+ directory: "/"
22
+ schedule:
23
+ interval: weekly
24
+ day: monday
25
+ open-pull-requests-limit: 5
26
+ labels:
27
+ - dependencies
28
+ - ci
29
+ commit-message:
30
+ prefix: chore
31
+ include: scope
32
+
33
+ # supabase/postgres image pin in workflows
34
+ - package-ecosystem: docker
35
+ directory: ".github/workflows"
36
+ schedule:
37
+ interval: weekly
38
+ day: monday
39
+ open-pull-requests-limit: 3
40
+ labels:
41
+ - dependencies
42
+ - ci
43
+ commit-message:
44
+ prefix: chore
45
+ include: scope
@@ -0,0 +1,73 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches: [main]
7
+
8
+ jobs:
9
+ python:
10
+ runs-on: ubuntu-latest
11
+ strategy:
12
+ matrix:
13
+ python-version: ["3.11", "3.12", "3.13"]
14
+ services:
15
+ postgres:
16
+ # Supabase's Postgres image bundles plpgsql_check, pgvector,
17
+ # pgsodium, pgjwt, etc., and creates the `auth` schema with
18
+ # `auth.uid()` / `auth.jwt()` helpers on first boot. This lets
19
+ # the plpgsql_coverage and (future) RLS-helper integration tests
20
+ # run against a realistic Supabase-shaped database.
21
+ image: supabase/postgres:15.8.1.040
22
+ env:
23
+ POSTGRES_PASSWORD: postgres
24
+ ports:
25
+ - 5432:5432
26
+ options: >-
27
+ --health-cmd "pg_isready -U postgres -d postgres"
28
+ --health-interval 10s
29
+ --health-timeout 5s
30
+ --health-retries 15
31
+ env:
32
+ SQLPROOF_TEST_DATABASE_URL: postgresql://postgres:postgres@127.0.0.1:5432/postgres
33
+ steps:
34
+ - uses: actions/checkout@v4
35
+ - uses: actions/setup-python@v6
36
+ with:
37
+ python-version: ${{ matrix.python-version }}
38
+ - uses: astral-sh/setup-uv@v5
39
+ - run: uv sync --extra dev
40
+ - name: Bring Postgres surface into lockstep with managed Supabase
41
+ uses: ./.github/actions/setup-supabase-test-db
42
+ with:
43
+ database-url: ${{ env.SQLPROOF_TEST_DATABASE_URL }}
44
+ verbose: 'true'
45
+ - run: uv run ruff check src/ tests/
46
+ - run: uv run pyright
47
+ - run: uv run mypy src/sqlproof/
48
+ - run: uv run pytest --cov=sqlproof --cov-fail-under=94 --cov-report=xml
49
+ - name: Upload coverage to Codecov
50
+ if: matrix.python-version == '3.11'
51
+ uses: codecov/codecov-action@v6
52
+ with:
53
+ files: ./coverage.xml
54
+ fail_ci_if_error: false
55
+ # Codecov v4 requires a token on protected branches even for
56
+ # public repos. Get the token from
57
+ # https://app.codecov.io/gh/alialavia/sqlproof/config/general
58
+ # and add as repo secret CODECOV_TOKEN.
59
+ token: ${{ secrets.CODECOV_TOKEN }}
60
+
61
+ website:
62
+ runs-on: ubuntu-latest
63
+ steps:
64
+ - uses: actions/checkout@v4
65
+ - uses: actions/setup-node@v4
66
+ with:
67
+ node-version: 20
68
+ cache: npm
69
+ cache-dependency-path: website/package-lock.json
70
+ - run: npm ci
71
+ working-directory: website
72
+ - run: npm run build
73
+ working-directory: website
@@ -33,6 +33,12 @@ jobs:
33
33
  - name: Build
34
34
  run: npm run build
35
35
  working-directory: website
36
+ env:
37
+ # Optional. Set under Settings → Secrets and variables → Actions
38
+ # to enable PostHog tracking on the deployed site. When unset
39
+ # the snippet is omitted from the build (see website/src/posthog.mjs).
40
+ PUBLIC_POSTHOG_KEY: ${{ secrets.PUBLIC_POSTHOG_KEY }}
41
+ PUBLIC_POSTHOG_HOST: ${{ secrets.PUBLIC_POSTHOG_HOST }}
36
42
 
37
43
  - name: Deploy to GitHub Pages
38
44
  uses: peaceiris/actions-gh-pages@v4
@@ -10,7 +10,7 @@ jobs:
10
10
  runs-on: ubuntu-latest
11
11
  steps:
12
12
  - uses: actions/checkout@v4
13
- - uses: actions/setup-python@v5
13
+ - uses: actions/setup-python@v6
14
14
  with:
15
15
  python-version: "3.11"
16
16
  - uses: astral-sh/setup-uv@v5
@@ -0,0 +1,42 @@
1
+ name: PR title
2
+
3
+ on:
4
+ pull_request:
5
+ types: [opened, edited, reopened, synchronize]
6
+
7
+ permissions:
8
+ pull-requests: read
9
+
10
+ jobs:
11
+ lint:
12
+ name: lint
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: amannn/action-semantic-pull-request@v6
16
+ env:
17
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
18
+ with:
19
+ # Accepted types — keep in sync with release-please-config.json
20
+ # `changelog-sections`. The action validates the PR title matches
21
+ # `<type>(<optional-scope>)!?: <subject>` per Conventional Commits.
22
+ types: |
23
+ feat
24
+ fix
25
+ perf
26
+ docs
27
+ refactor
28
+ test
29
+ chore
30
+ ci
31
+ build
32
+ style
33
+ revert
34
+ # Scopes are optional; we don't enforce an allowlist (subsystem
35
+ # naming is too fluid to constrain at this scale).
36
+ requireScope: false
37
+ # Subject must start with a lowercase letter to match the
38
+ # project's existing commit style (`feat(core): skip insert ...`).
39
+ subjectPattern: ^[a-z].+$
40
+ subjectPatternError: |
41
+ The PR title subject must start with a lowercase letter
42
+ (e.g. "feat(core): add support for ..." not "Add support for ...").
@@ -0,0 +1,33 @@
1
+ name: release-please
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+
7
+ # No top-level permissions: release-please acts via the GitHub App token
8
+ # below, not the default GITHUB_TOKEN. The App's installation token
9
+ # carries its own permissions (contents:write, pull_requests:write,
10
+ # metadata:read) configured when the App was created.
11
+
12
+ jobs:
13
+ release-please:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ # Mint a short-lived installation token from the `sqlproof-releases`
17
+ # GitHub App. Tags + commits pushed with this token DO trigger
18
+ # downstream workflows (unlike the default GITHUB_TOKEN, which
19
+ # GitHub Actions explicitly blocks from triggering recursive runs).
20
+ # That's what lets release.yml fire when release-please creates a
21
+ # v*.*.* tag.
22
+ - name: Mint release-please token from sqlproof-releases App
23
+ uses: actions/create-github-app-token@v1
24
+ id: app-token
25
+ with:
26
+ app-id: ${{ secrets.RELEASE_PLEASE_APP_ID }}
27
+ private-key: ${{ secrets.RELEASE_PLEASE_PRIVATE_KEY }}
28
+
29
+ - uses: googleapis/release-please-action@v5
30
+ with:
31
+ token: ${{ steps.app-token.outputs.token }}
32
+ config-file: release-please-config.json
33
+ manifest-file: .release-please-manifest.json
@@ -0,0 +1,71 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+ # Manual fallback. Use this to publish a tag that was created before
8
+ # the sqlproof-releases GitHub App was wired into release-please.yml
9
+ # (where tag-push didn't auto-trigger this workflow), or to retry a
10
+ # failed publish without re-tagging. Specify the tag in the input.
11
+ workflow_dispatch:
12
+ inputs:
13
+ tag:
14
+ description: 'Tag to build and publish (e.g. v0.2.0)'
15
+ required: true
16
+ type: string
17
+
18
+ jobs:
19
+ build:
20
+ runs-on: ubuntu-latest
21
+ services:
22
+ postgres:
23
+ # Mirror the CI service container so pre-publish testing
24
+ # exercises the same integration surface that PR CI does.
25
+ image: supabase/postgres:15.8.1.040
26
+ env:
27
+ POSTGRES_PASSWORD: postgres
28
+ ports:
29
+ - 5432:5432
30
+ options: >-
31
+ --health-cmd "pg_isready -U postgres -d postgres"
32
+ --health-interval 10s
33
+ --health-timeout 5s
34
+ --health-retries 15
35
+ env:
36
+ SQLPROOF_TEST_DATABASE_URL: postgresql://postgres:postgres@127.0.0.1:5432/postgres
37
+ steps:
38
+ - uses: actions/checkout@v4
39
+ with:
40
+ # For workflow_dispatch, check out the tag the operator passed
41
+ # as input. For push events, default behavior checks out the
42
+ # tag-ref that triggered the workflow (no override needed).
43
+ ref: ${{ inputs.tag || github.ref }}
44
+ - uses: actions/setup-python@v6
45
+ with:
46
+ python-version: "3.11"
47
+ - uses: astral-sh/setup-uv@v5
48
+ - run: uv sync --extra dev
49
+ - name: Bring Postgres surface into lockstep with managed Supabase
50
+ uses: ./.github/actions/setup-supabase-test-db
51
+ with:
52
+ database-url: ${{ env.SQLPROOF_TEST_DATABASE_URL }}
53
+ - run: uv run pytest -m "not nocover"
54
+ - run: uv build
55
+ - uses: actions/upload-artifact@v4
56
+ with:
57
+ name: dist
58
+ path: dist/
59
+
60
+ publish:
61
+ needs: build
62
+ runs-on: ubuntu-latest
63
+ environment: pypi
64
+ permissions:
65
+ id-token: write
66
+ steps:
67
+ - uses: actions/download-artifact@v4
68
+ with:
69
+ name: dist
70
+ path: dist/
71
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,45 @@
1
+ name: uv-lock-refresh
2
+
3
+ # Dependabot's `pip` ecosystem bumps declared deps in pyproject.toml but
4
+ # doesn't know how to regenerate uv.lock. This workflow runs `uv lock` on
5
+ # every dependabot PR and pushes the updated lockfile back to the PR
6
+ # branch so the merge is internally consistent.
7
+
8
+ on:
9
+ pull_request:
10
+ paths:
11
+ - pyproject.toml
12
+
13
+ permissions:
14
+ contents: write
15
+
16
+ jobs:
17
+ refresh:
18
+ # Only run on PRs opened by Dependabot. Other PRs that touch
19
+ # pyproject.toml should update uv.lock manually (and reviewers can
20
+ # catch drift).
21
+ if: github.actor == 'dependabot[bot]'
22
+ runs-on: ubuntu-latest
23
+ steps:
24
+ - uses: actions/checkout@v4
25
+ with:
26
+ ref: ${{ github.head_ref }}
27
+ # GH Actions can't push back to a PR branch by default; use a
28
+ # PAT-less approach via `actions/checkout` with the default
29
+ # token, which works because we're pushing to the same repo
30
+ # the workflow runs in.
31
+ token: ${{ secrets.GITHUB_TOKEN }}
32
+ - uses: astral-sh/setup-uv@v5
33
+ - name: Refresh uv.lock
34
+ run: uv lock
35
+ - name: Commit and push if lockfile changed
36
+ run: |
37
+ if git diff --quiet uv.lock; then
38
+ echo "uv.lock unchanged; nothing to do."
39
+ exit 0
40
+ fi
41
+ git config user.name "github-actions[bot]"
42
+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
43
+ git add uv.lock
44
+ git commit -m "chore(deps): refresh uv.lock"
45
+ git push
@@ -10,4 +10,6 @@ __pycache__/
10
10
  .pytest_cache/
11
11
  .hypothesis/
12
12
  .coverage
13
+ coverage.xml
14
+ htmlcov/
13
15
  .venv/
@@ -0,0 +1,3 @@
1
+ {
2
+ ".": "0.2.2"
3
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "$schema": "https://sqlproof.dev/schemas/counterexample-v1.json",
3
+ "dataset": {
4
+ "orders": [
5
+ {
6
+ "id": 1,
7
+ "total": 0
8
+ }
9
+ ]
10
+ },
11
+ "failure": {
12
+ "kind": "UndefinedTable",
13
+ "locals": {},
14
+ "message": "relation \"orders\" does not exist\nLINE 1: SELECT id FROM orders\n ^",
15
+ "traceback": []
16
+ },
17
+ "property_name": "property_fails",
18
+ "row_context": {},
19
+ "runs": 110,
20
+ "schema_fingerprint": "sha256:10216d67c52fe4492028569c0a44ea070c450fb3488ad02a3599c35192366658",
21
+ "seed": null,
22
+ "shrink_steps": 0,
23
+ "version": 1
24
+ }