Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ on:
push:
pull_request:

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

jobs:
build:

Expand Down Expand Up @@ -42,4 +46,16 @@ jobs:
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
token: ${{ secrets.CODECOV_TOKEN }}

package:
name: Build and check distribution
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: "3.12"
- run: python -m pip install --upgrade pip build twine
- run: python -m build
- run: twine check dist/*
192 changes: 113 additions & 79 deletions .github/workflows/publish-to-pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,96 +3,130 @@ name: Publish to PyPI
on:
push:
tags:
- 'v*' # Triggers on version tags like v1.0.0, v1.0.1, etc.
- "v*" # e.g. v2.0.0

permissions:
contents: write
contents: read

jobs:
verify:
name: Verify tag matches package version
runs-on: ubuntu-latest
outputs:
version: ${{ steps.v.outputs.version }}
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Compare tag with natquery.__version__
id: v
run: |
PKG=$(python -c "import re,pathlib;print(re.search(r'__version__\s*=\s*[\"\\']([^\"\\']+)', pathlib.Path('src/natquery/__init__.py').read_text()).group(1))")
TAG="${GITHUB_REF_NAME#v}"
echo "package=$PKG tag=$TAG"
if [ "$PKG" != "$TAG" ]; then
echo "::error::Tag v$TAG does not match natquery.__version__ ($PKG)"; exit 1
fi
grep -q "^## \[$PKG\]" CHANGELOG.md || { echo "::error::CHANGELOG.md has no entry for $PKG"; exit 1; }
echo "version=$PKG" >> "$GITHUB_OUTPUT"

test:
needs: verify
runs-on: ${{ matrix.os }}
strategy:
fail-fast: true
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python-version: ['3.10', '3.11', '3.12']

python-version: ["3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -e ".[dev]"

- name: Lint with ruff
run: |
ruff check .

- name: Format check with black
run: |
black --check src tests

- name: Run tests
run: |
pytest tests -v --cov=src/natquery --cov-report=xml

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}

deploy:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -e ".[dev]"
- name: Format check with black
run: black --check .
- name: Lint with ruff
run: ruff check .
- name: Run tests
run: pytest --cov=natquery --cov-report=xml --cov-report=term
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}

build:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
with:
python-version: "3.12"
- run: python -m pip install --upgrade pip build twine
- run: python -m build
- run: twine check dist/*
- uses: actions/upload-artifact@v4
with:
name: dist
path: dist/

publish:
name: Publish to PyPI
needs: [verify, build]
runs-on: ubuntu-latest
environment: pypi

steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.12'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install build wheel twine

- name: Build distribution
run: |
python -m build

- name: Check distribution
run: |
twine check dist/*

- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_API_TOKEN }}
skip-existing: true

- name: Create GitHub Release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref_name }}
body: |
# NatQuery ${{ github.ref_name }}

Release published to PyPI.

Install with:
```bash
pip install natquery==${{ github.ref_name }}
```
draft: false
prerelease: false
- uses: actions/download-artifact@v4
with:
name: dist
path: dist/
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_API_TOKEN }}
skip-existing: true

release:
name: GitHub Release
needs: [verify, publish]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v6
- uses: actions/download-artifact@v4
with:
name: dist
path: dist/
- name: Extract release notes from CHANGELOG.md
env:
VERSION: ${{ needs.verify.outputs.version }}
run: |
awk -v v="$VERSION" '
$0 ~ "^## \\[" v "\\]" {f=1; next}
f && /^## \[/ {exit}
f && /^---$/ {next}
f {print}
' CHANGELOG.md > release_notes.md
{
echo
echo "## Install"
echo
echo '```bash'
echo "pip install natquery==$VERSION"
echo '```'
echo
echo "PyPI: https://pypi.org/project/natquery/$VERSION/"
} >> release_notes.md
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
name: NatQuery ${{ needs.verify.outputs.version }}
body_path: release_notes.md
files: dist/*
prerelease: ${{ contains(needs.verify.outputs.version, '-') }}
17 changes: 16 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -208,4 +208,19 @@ __marimo__/


#.natquery files
.natquery/
.natquery/
# NatQuery workspace / local artifacts
.natquery/
*.db
erp/bench/*.log
# LaTeX build output
report/*.aux
report/*.log
report/*.out
report/*.toc
report/*.bbl
report/*.blg
report/*.lof
report/*.lot
report/*.fls
report/*.fdb_latexmk
52 changes: 50 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,52 @@
# Changelog
# Changelog

All notable changes to NatQuery are documented here. The format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project uses
[Semantic Versioning](https://semver.org/).

## [2.0.0] - 2026-11-01

NatQuery 2.0.0 turns the 1.x prototype into a governed, auditable natural-language
interface for PostgreSQL. The LLM only ever *proposes* SQL; a deterministic enforcement
layer decides whether it runs.

### Added
- **SQL enforcer** (sqlglot AST based): single read-only `SELECT`, allow-listed tables and
columns, blocked functions and system catalogs, forced `LIMIT`, statement timeout.
- **Role policy engine** with YAML/JSON policies: per-role table/column access, row filters,
column masks and abstract (inheritable) roles; `natquery policy init` scaffolds examples.
- **Multi-schema mode** and **PostgreSQL Row-Level Security** integration via
`db_session_vars` and `SET LOCAL ROLE`, so the database enforces what the policy declares.
- **Hash-chained audit log** (tamper-evident, `verify()`), secret scrubbing in logs,
private (0600/0700) config and workspace files written atomically.
- **Pluggable authentication** (local user store with hashed passwords and strength
checks; extra providers through the `natquery.auth_providers` entry-point group).
- **Schema intelligence**: weighted table ranking, wider-schema retry, value hints
(`natquery schema hints`) and per-column semantics merged into the prompt.
- **Benchmarks**: BIRD dev evaluation harness (`benchmarks/bird`), 5-case security suite
(`benchmarks/security`) and a 40-question ERP benchmark (`erp/`), with results.
- **ERP test bed**: 87 tables / 549 columns / 10 roles / ~368k rows reproducible generator.
- **Documentation**: `docs/ARCHITECTURE.md`, `docs/BIRD_REPORT.md`, `docs/SECURITY_REPORT.md`
and the full project report in LaTeX (`report/`).
- 855 tests (unit + PostgreSQL integration), >= 90 % coverage gate.

### Changed
- Project layout, README and packaging rewritten; the wheel now ships only `natquery`
(benchmarks and ERP assets live in the repository, not on PyPI).
- CI and release workflows aligned: same lint/format/test gates, tag-vs-version check,
release notes generated from this changelog.
- Code formatted with black 25.1.0 and linted with ruff 0.15.6 across the whole repository.

### Results
- BIRD dev (500 questions): official EX 45.6 %, tolerant scorer 50.6 %.
- ERP 40-question benchmark: 28/40 (70 %), 0 data leaks across 5 adversarial prompts.

### Notes
- Version `2.0.0` is the first release with the governance layer; configuration written by
1.x remains readable, but policies are new and must be created with `natquery policy init`.

---

---

## [1.0.1] - 2026-04-14
Expand Down Expand Up @@ -39,4 +87,4 @@
- EXPLAIN ANALYZE integration
- Cost analyzer for PostgreSQL execution plans
- Index recommender for query optimization
- Performance API for tracking and comparing query runs
- Performance API for tracking and comparing query runs
Loading
Loading