Skip to content
Open
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
48 changes: 48 additions & 0 deletions .github/workflows/release-eql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,51 @@ 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: Validate documentation
run: |
mise run docs:validate

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

- 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
18 changes: 18 additions & 0 deletions .github/workflows/test-eql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,27 @@ defaults:
shell: bash -l {0}

jobs:
validate-docs:
name: "Validate SQL Documentation"
runs-on: ubuntu-latest-m

steps:
- uses: actions/checkout@v4

- uses: jdx/mise-action@v2
with:
version: 2025.1.6
install: true
cache: true

- name: Validate SQL documentation
run: |
mise run docs:validate

test:
name: "Test EQL SQL components"
runs-on: ubuntu-latest-m
needs: validate-docs

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

# Generated documentation
docs/api/



# jupyter notebook
Expand Down
148 changes: 148 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
# 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
- `mise run docs:generate` - Generate API documentation (requires doxygen)
- `mise run docs:validate` - Validate documentation coverage and tags

### 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
tasks/check-doc-coverage.sh # Check 100% coverage
tasks/validate-required-tags.sh # Verify @brief, @param, @return tags
tasks/validate-documented-sql.sh # 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.

## 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)
95 changes: 95 additions & 0 deletions Doxyfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# 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
#---------------------------------------------------------------------------

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

HTML_OUTPUT = html
HTML_FILE_EXTENSION = .html
HTML_DYNAMIC_SECTIONS = YES

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

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

# Treat SQL files as C++ for parsing
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/doxygen-filter.sh"
FILTER_SOURCE_FILES = YES

#---------------------------------------------------------------------------
# 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

#---------------------------------------------------------------------------
# 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