Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
36c56d9
docs(sql): add complete Doxygen documentation (Phases 1-4)
tobyhede Oct 29, 2025
a2cbf00
docs: add Doxygen infrastructure and tooling
tobyhede Oct 29, 2025
048e26f
ci: add documentation validation to test workflow
tobyhede Oct 29, 2025
1fac7d7
docs(sql): add Doxygen comments to version template
tobyhede Oct 29, 2025
85463d8
docs(sql): fix documentation validation errors
tobyhede Oct 29, 2025
7de4031
fix: restore correct SQL code from phase-4-doxygen
tobyhede Oct 29, 2025
4deefe9
fix(docs): skip auto-generated files in validation
tobyhede Oct 29, 2025
0320a1f
docs: add Doxygen configuration and validation scripts
tobyhede Oct 29, 2025
e8fce88
docs: add documentation build tasks to mise
tobyhede Oct 29, 2025
000a9f2
docs: add packaging script for documentation archives
tobyhede Oct 29, 2025
bfb24ee
fix(docs): skip auto-generated files in validation
tobyhede Oct 29, 2025
c38d95d
ci: add documentation publishing to release workflow
tobyhede Oct 29, 2025
638822a
chore: ignore generated documentation directory
tobyhede Oct 29, 2025
477b3e2
refactor: use auto-discovered docs-package task
tobyhede Oct 29, 2025
b43ac75
test: move tests from TOML to standalone shell scripts
auxesis Nov 6, 2025
84ed601
test: move documentation tests under docs:validate:*
auxesis Nov 6, 2025
6546640
test: check that the source directory exists before running tests
auxesis Nov 6, 2025
eb0040d
build: namespace doxygen tasks under docs:*
auxesis Nov 6, 2025
2498223
build: ensure latest bash is used
auxesis Nov 6, 2025
e698958
test: ensure the documented SQL is validated
auxesis Nov 6, 2025
e8b7dfa
ci: ensure database is available before running docs:validate
auxesis Nov 6, 2025
13b806b
refactor: go back to relative paths, so the output is less noisy
auxesis Nov 6, 2025
4a7ad7d
feat(docs): add XML and Markdown documentation generation
tobyhede Oct 30, 2025
b5f0fac
fix(docs): resolve validation failures due to SQL file dependencies
tobyhede Nov 10, 2025
034a780
fix(ci): add default environment variables to docker-compose for CI
tobyhede Nov 11, 2025
dc78bc1
refactor(ci): consolidate validation into test matrix for consistency
tobyhede Nov 11, 2025
46117b6
ci: remove validate from release
tobyhede Nov 11, 2025
fab1b00
fix(docs): use dedicated package script instead of inline task
tobyhede Nov 11, 2025
896c2bb
fix(docs): correct Doxygen parameter documentation format
tobyhede Nov 11, 2025
7834c35
refactor: remove duplicate jobs
auxesis Nov 11, 2025
6bb1bc1
fix: remove output about a file that doesn't exist
auxesis Nov 11, 2025
78aa5a6
refactor: make markdown generation idiomatic
auxesis Nov 11, 2025
2dda98d
fix(docs): correct XML to Markdown conversion for SQL documentation
tobyhede Nov 11, 2025
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
45 changes: 45 additions & 0 deletions .github/workflows/release-eql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,48 @@ jobs:
--header "Content-Type: application/json" \
--header "Authorization: ${{ secrets.MULTITUDES_ACCESS_TOKEN }}" \
--data '{"commitSha": "${{ github.sha }}", "environmentName":"production"}'

publish-docs:
runs-on: ubuntu-latest
name: Build and Publish Documentation
if: ${{ github.event_name != 'release' || contains(github.event.release.tag_name, 'eql') }}
timeout-minutes: 10

steps:
- uses: actions/checkout@v4

- uses: jdx/mise-action@v2
with:
version: 2025.1.6 # [default: latest] mise version to install
install: true # [default: true] run `mise install`
cache: true # [default: true] cache mise using GitHub's cache

- name: Install Doxygen
run: |
sudo apt-get update
sudo apt-get install -y doxygen

- name: Generate documentation
run: |
mise run docs:generate
mise run docs:generate:markdown

- name: Package documentation
run: |
mise run docs:package ${{ github.event.release.tag_name }}

- name: Upload documentation artifacts
uses: actions/upload-artifact@v4
with:
name: eql-docs
path: |
release/eql-docs-*.zip
release/eql-docs-*.tar.gz

- name: Publish documentation to release
uses: softprops/action-gh-release@v2
if: startsWith(github.ref, 'refs/tags/')
with:
files: |
release/eql-docs-*.zip
release/eql-docs-*.tar.gz
11 changes: 9 additions & 2 deletions .github/workflows/test-eql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ defaults:

jobs:
test:
name: "Test EQL SQL components"
runs-on: blacksmith-16vcpu-ubuntu-2204
name: "Test & Validate EQL (Postgres ${{ matrix.postgres-version }})"
runs-on: ubuntu-latest-m

strategy:
fail-fast: false
Expand All @@ -51,8 +51,15 @@ jobs:
run: |
mise run postgres:up postgres-${POSTGRES_VERSION} --extra-args "--detach --wait"

- name: Validate SQL documentation (Postgres ${{ matrix.postgres-version }})
run: |
mise run docs:validate

- name: Test EQL for Postgres ${{ matrix.postgres-version }}
run: |
export active_rust_toolchain=$(rustup show active-toolchain | cut -d' ' -f1)
rustup component add --toolchain ${active_rust_toolchain} rustfmt clippy
mise run --output prefix test --postgres ${POSTGRES_VERSION}



3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,9 @@ cipherstash-proxy.toml
# build artifacts
release/

# Generated documentation
docs/api/



# jupyter notebook
Expand Down
169 changes: 169 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Development Commands

This project uses `mise` for task management. Common commands:

- `mise run build` (alias: `mise r b`) - Build SQL into single release file
- `mise run test` (alias: `mise r test`) - Build, reset and run tests
- `mise run postgres:up` - Start PostgreSQL container
- `mise run postgres:down` - Stop PostgreSQL containers
- `mise run reset` - Reset database state
- `mise run clean` (alias: `mise r k`) - Clean release files

### Documentation
- `mise run docs:generate` - Generate API documentation (requires doxygen)
- Outputs XML (primary) and HTML (preview) formats
- XML suitable for downstream processing/website integration
- See `docs/api/README.md` for XML format details
- `mise run docs:generate:markdown` - Convert XML to Markdown API reference
- Generates single-file API reference: `docs/api/markdown/API.md`
- Includes 84 documented functions with parameters, return values, and source links
- `mise run docs:validate` - Validate documentation coverage and tags
- `mise run docs:package` - Package XML docs for distribution (~230KB archive)

### Testing
- Run all tests: `mise run test`
- Run specific test: `mise run test --test <test_name>`
- Run tests against specific PostgreSQL version: `mise run test --postgres 14|15|16|17`
- Tests are located in `*_test.sql` files alongside source code

### Build System
- Dependencies are resolved using `-- REQUIRE:` comments in SQL files
- Build outputs to `release/` directory:
- `cipherstash-encrypt.sql` - Main installer
- `cipherstash-encrypt-supabase.sql` - Supabase-compatible installer
- `cipherstash-encrypt-uninstall.sql` - Uninstaller

## Project Architecture

This is the **Encrypt Query Language (EQL)** - a PostgreSQL extension for searchable encryption. Key architectural components:

### Core Structure
- **Schema**: All EQL functions/types are in `eql_v2` PostgreSQL schema
- **Main Type**: `eql_v2_encrypted` - composite type for encrypted columns (stored as JSONB)
- **Configuration**: `eql_v2_configuration` table tracks encryption configs
- **Index Types**: Various encrypted index types (blake3, hmac_256, bloom_filter, ore variants)

### Directory Structure
- `src/` - Modular SQL components with dependency management
- `src/encrypted/` - Core encrypted column type implementation
- `src/operators/` - SQL operators for encrypted data comparisons
- `src/config/` - Configuration management functions
- `src/blake3/`, `src/hmac_256/`, `src/bloom_filter/`, `src/ore_*` - Index implementations
- `tasks/` - mise task scripts
- `tests/` - Test files (PostgreSQL 14-17 support)
- `release/` - Generated SQL installation files

### Key Concepts
- **Dependency System**: SQL files declare dependencies via `-- REQUIRE:` comments
- **Encrypted Data**: Stored as JSONB payloads with metadata
- **Index Terms**: Transient types for search operations (blake3, hmac_256, etc.)
- **Operators**: Support comparisons between encrypted and plain JSONB data
- **CipherStash Proxy**: Required for encryption/decryption operations

### Testing Infrastructure
- Tests run against PostgreSQL 14, 15, 16, 17 using Docker containers
- Container configuration in `tests/docker-compose.yml`
- Test helpers in `tests/test_helpers.sql`
- Database connection: `localhost:7432` (cipherstash/password)
- **Rust/SQLx Tests**: Modern test framework in `tests/sqlx/` (see README there)

## Project Learning & Retrospectives

Valuable lessons and insights from completed work:

- **SQLx Test Migration (2025-10-24)**: See `docs/retrospectives/2025-10-24-sqlx-migration-retrospective.md`
- Migrated 40 SQL assertions to Rust/SQLx (100% coverage)
- Key insights: Blake3 vs HMAC differences, batch-review pattern effectiveness, coverage metric definitions
- Lessons: TDD catches setup issues, infrastructure investment pays off, code review after each batch prevents compound errors

## Documentation Standards

### Doxygen Comments

All SQL functions and types must be documented using Doxygen-style comments:

- **Comment Style**: Use `--!` prefix for Doxygen comments (not `--`)
- **Required Tags**:
- `@brief` - Short description (required for all functions/files)
- `@param` - Parameter description (required for functions with parameters)
- `@return` - Return value description (required for functions with non-void returns)
- **Optional Tags**:
- `@throws` - Exception conditions
- `@note` - Important notes or caveats
- `@warning` - Warning messages (e.g., for DDL-executing functions)
- `@see` - Cross-references to related functions
- `@example` - Usage examples
- `@internal` - Mark internal/private functions
- `@file` - File-level documentation

### Documentation Example

```sql
--! @brief Create encrypted index configuration
--!
--! Initializes a new encrypted index configuration for a table column.
--! The configuration tracks encryption settings and index types.
--!
--! @param p_table_name text Table name (schema-qualified)
--! @param p_column_name text Column name to encrypt
--! @param p_index_type text Type of encrypted index (blake3, hmac_256, etc.)
--!
--! @return uuid Configuration ID for the created index
--!
--! @throws unique_violation If configuration already exists for this column
--!
--! @note This function executes DDL and modifies database schema
--! @see eql_v2.activate_encrypted_index
--!
--! @example
--! -- Create blake3 index configuration
--! SELECT eql_v2.create_encrypted_index(
--! 'public.users',
--! 'email',
--! 'blake3'
--! );
CREATE FUNCTION eql_v2.create_encrypted_index(...)
```

### Validation Tools

Verify documentation quality:

```bash
# Using mise (recommended - validates coverage and tags)
mise run docs:validate

# Or run individual scripts directly
mise run docs:validate:coverage # Check 100% coverage
mise run docs:validate:required-tags # Verify @brief, @param, @return tags
mise run docs:validate:documented-sql # Validate SQL syntax (requires database)
```

### Template Files

Template files (e.g., `version.template`) must be documented. The Doxygen comments are automatically included in generated files during build.

### Generated Documentation Format

The documentation is generated in **XML format** as the primary output:

- **Location**: `docs/api/xml/`
- **Format**: Doxygen XML (v1.15.0) with XSD schemas
- **Usage**: Machine-readable, suitable for downstream processing
- **Publishing**: Package with `mise run docs:package` → creates `eql-docs-xml-2.x.tar.gz`
- **Integration**: See `docs/api/README.md` for XML structure and transformation examples

HTML output is also generated in `docs/api/html/` for local preview only.

## Development Notes

- SQL files are modular - put operator wrappers in `operators.sql`, implementation in `functions.sql`
- All SQL files must have `-- REQUIRE:` dependency declarations
- Test files end with `_test.sql` and live alongside source files
- Build system uses `tsort` to resolve dependency order
- Supabase build excludes operator classes (not supported)
- **Documentation**: All functions/types must have Doxygen comments (see Documentation Standards above)
125 changes: 125 additions & 0 deletions Doxyfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# Doxyfile for Encrypt Query Language (EQL)
# PostgreSQL extension for searchable encryption

#---------------------------------------------------------------------------
# Project Settings
#---------------------------------------------------------------------------

PROJECT_NAME = "Encrypt Query Language (EQL)"
PROJECT_NUMBER = "2.x"
PROJECT_BRIEF = "PostgreSQL extension for searchable encryption"

OUTPUT_DIRECTORY = docs/api
CREATE_SUBDIRS = NO

#---------------------------------------------------------------------------
# Build Settings
#---------------------------------------------------------------------------
# PRIMARY OUTPUT: XML for downstream processing
# HTML: Optional, for local preview only
# MARKDOWN: Experimental (may not generate in all Doxygen versions)

GENERATE_HTML = YES
GENERATE_LATEX = NO
GENERATE_XML = YES
GENERATE_MAN = NO
GENERATE_MARKDOWN = YES

HTML_OUTPUT = html
HTML_FILE_EXTENSION = .html
HTML_DYNAMIC_SECTIONS = YES

# XML Settings - Primary documentation format
XML_OUTPUT = xml
XML_PROGRAMLISTING = YES

# Markdown generation not supported in Doxygen 1.15.0
# Use external tools to convert XML to Markdown:
# - doxybook2 (C++, recommended): https://github.com/matusnovak/doxybook2
# - moxygen (Node.js): https://github.com/sourcey/moxygen
# - esp-doxybook (Python): https://pypi.org/project/esp-doxybook/
# See docs/api/README.md for integration examples

#---------------------------------------------------------------------------
# Input Settings
#---------------------------------------------------------------------------

INPUT = src/
FILE_PATTERNS = *.sql *.template
RECURSIVE = YES
EXCLUDE_PATTERNS = *_test.sql

# Treat SQL files as C++ for parsing
# NOTE: Doxygen has no native SQL support. Parsing as C++ is imperfect but allows
# extraction of function names and documentation comments.
EXTENSION_MAPPING = sql=C++ template=C++

# CRITICAL: Input filter to convert SQL comments (--!) to C++ style (//!)
# This is REQUIRED for Doxygen to recognize SQL comments
INPUT_FILTER = "tasks/docs/doxygen-filter.sh"
FILTER_SOURCE_FILES = YES

# Source patterns - treat SQL keywords more gracefully
FILTER_PATTERNS =

#---------------------------------------------------------------------------
# Extraction Settings
#---------------------------------------------------------------------------

EXTRACT_ALL = YES
EXTRACT_PRIVATE = YES
EXTRACT_STATIC = YES

HIDE_UNDOC_MEMBERS = NO
HIDE_UNDOC_CLASSES = NO

SHOW_FILES = YES
SHOW_NAMESPACES = YES

#---------------------------------------------------------------------------
# Documentation Settings
#---------------------------------------------------------------------------

JAVADOC_AUTOBRIEF = YES
OPTIMIZE_OUTPUT_FOR_C = YES

# Disable some C++-specific features that don't apply to SQL
BUILTIN_STL_SUPPORT = NO
CPP_CLI_SUPPORT = NO
IDL_PROPERTY_SUPPORT = NO

# Enable better handling of functions/procedures
EXTRACT_LOCAL_METHODS = YES
SORT_MEMBER_DOCS = YES
SORT_BRIEF_DOCS = YES

#---------------------------------------------------------------------------
# Warning Settings
#---------------------------------------------------------------------------

QUIET = NO
WARNINGS = YES
WARN_IF_UNDOCUMENTED = NO
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = NO

#---------------------------------------------------------------------------
# Source Browsing
#---------------------------------------------------------------------------

SOURCE_BROWSER = YES
INLINE_SOURCES = NO
REFERENCED_BY_RELATION = YES
REFERENCES_RELATION = YES

#---------------------------------------------------------------------------
# Alphabetical Index
#---------------------------------------------------------------------------

ALPHABETICAL_INDEX = YES

#---------------------------------------------------------------------------
# Search Engine
#---------------------------------------------------------------------------

SEARCHENGINE = YES
Loading