Skip to content

fix memory leak: pfree() text_to_cstring() results #249

fix memory leak: pfree() text_to_cstring() results

fix memory leak: pfree() text_to_cstring() results #249

Workflow file for this run

name: CI/CD Pipeline
on:
push:
branches: [main]
paths-ignore:
- '**.md'
- 'docs/**'
- 'LICENSE'
- '.agents/commands'
- '.github/ISSUE_TEMPLATE/**'
- '.github/PULL_REQUEST_TEMPLATE.md'
- '.gitignore'
- 'gh-issue'
pull_request:
branches: [main]
paths-ignore:
- '**.md'
- 'docs/**'
- 'LICENSE'
- '.agents/commands'
- '.github/ISSUE_TEMPLATE/**'
- '.github/PULL_REQUEST_TEMPLATE.md'
- '.gitignore'
- 'gh-issue'
# Required permissions for CodeQL action
permissions:
contents: read
security-events: write
actions: read
env:
CMAKE_BUILD_TYPE: Release
jobs:
build-and-test:
name: Build and Test
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-24.04, macos-latest]
pg_version: ["14", "15", "16", "17", "18"]
steps:
- name: Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
submodules: recursive
fetch-depth: 0
- name: Verify submodules
run: |
echo "Verifying submodule initialization..."
git submodule status
ls -la third_party/ai-sdk-cpp/CMakeLists.txt
- name: Cache dependencies
uses: actions/cache@cdf6c1fa76f9f475f3d7449005a359c84ca0f306 # v5.0.3
with:
path: |
~/.cache/vcpkg
build/_deps
key: ${{ runner.os }}-pg${{ matrix.pg_version }}-${{ hashFiles('CMakeLists.txt', 'third_party/ai-sdk-cpp/CMakeLists.txt') }}
restore-keys: |
${{ runner.os }}-pg${{ matrix.pg_version }}-
- name: Install dependencies (Ubuntu)
if: matrix.os == 'ubuntu-24.04'
run: |
# Install PostgreSQL from official APT repository
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
sudo apt-get update
sudo apt-get install -y \
build-essential \
cmake \
libssl-dev \
libcurl4-openssl-dev \
pkg-config \
gettext \
libz-dev \
postgresql-${{ matrix.pg_version }} \
postgresql-server-dev-${{ matrix.pg_version }}
- name: Install dependencies (macOS)
if: matrix.os == 'macos-latest'
run: |
brew update
brew install cmake openssl pkg-config gettext postgresql@${{ matrix.pg_version }}
# Link gettext for macOS
brew link --force gettext
- name: Setup PostgreSQL (Ubuntu)
if: matrix.os == 'ubuntu-24.04'
run: |
# Use version-specific binaries (similar to macOS approach)
PG_BIN=/usr/lib/postgresql/${{ matrix.pg_version }}/bin
PGDATA=/tmp/pgdata-${{ matrix.pg_version }}
# Initialize a fresh database cluster
sudo mkdir -p $PGDATA
sudo chown postgres:postgres $PGDATA
sudo -u postgres $PG_BIN/initdb -D $PGDATA
# Start PostgreSQL on a fixed port
sudo -u postgres $PG_BIN/pg_ctl -D $PGDATA -l /tmp/pg.log -o "-p 5432" start
sleep 2
# Create user and database
sudo -u postgres $PG_BIN/createuser -p 5432 -s $USER
sudo -u postgres $PG_BIN/createdb -p 5432 testdb
echo "PG_BIN=$PG_BIN" >> $GITHUB_ENV
- name: Setup PostgreSQL (macOS)
if: matrix.os == 'macos-latest'
run: |
# Add PostgreSQL to PATH
echo "$(brew --prefix postgresql@${{ matrix.pg_version }})/bin" >> $GITHUB_PATH
export PATH="$(brew --prefix postgresql@${{ matrix.pg_version }})/bin:$PATH"
brew services start postgresql@${{ matrix.pg_version }}
sleep 5
# Verify tools are available
which psql || echo "psql not found"
which createdb || echo "createdb not found"
createdb testdb || true
- name: Configure CMake
run: |
if [[ "${{ matrix.os }}" == "macos-latest" ]]; then
PG_CONFIG=$(brew --prefix postgresql@${{ matrix.pg_version }})/bin/pg_config
OPENSSL_ROOT_DIR=$(brew --prefix openssl)
cmake -B build -DCMAKE_BUILD_TYPE=${{env.CMAKE_BUILD_TYPE}} \
-DPG_CONFIG="$PG_CONFIG" \
-DOPENSSL_ROOT_DIR="$OPENSSL_ROOT_DIR"
else
# Ubuntu: Use version-specific pg_config path
PG_CONFIG=/usr/lib/postgresql/${{ matrix.pg_version }}/bin/pg_config
cmake -B build -DCMAKE_BUILD_TYPE=${{env.CMAKE_BUILD_TYPE}} \
-DPG_CONFIG="$PG_CONFIG"
fi
- name: Build extension
run: |
cmake --build build --config ${{env.CMAKE_BUILD_TYPE}} --parallel $(nproc 2>/dev/null || sysctl -n hw.ncpu)
- name: Build and run unit tests
run: |
# Configure with tests enabled
if [[ "${{ matrix.os }}" == "macos-latest" ]]; then
PG_CONFIG=$(brew --prefix postgresql@${{ matrix.pg_version }})/bin/pg_config
OPENSSL_ROOT_DIR=$(brew --prefix openssl)
cmake -B build_tests -DCMAKE_BUILD_TYPE=${{env.CMAKE_BUILD_TYPE}} \
-DBUILD_TESTS=ON \
-DPG_CONFIG="$PG_CONFIG" \
-DOPENSSL_ROOT_DIR="$OPENSSL_ROOT_DIR"
else
PG_CONFIG=/usr/lib/postgresql/${{ matrix.pg_version }}/bin/pg_config
cmake -B build_tests -DCMAKE_BUILD_TYPE=${{env.CMAKE_BUILD_TYPE}} \
-DBUILD_TESTS=ON \
-DPG_CONFIG="$PG_CONFIG"
fi
# Build test executable
cmake --build build_tests --target pg_ai_query_tests --parallel $(nproc 2>/dev/null || sysctl -n hw.ncpu)
# Run unit tests
echo "=== Running Unit Tests ==="
cd build_tests && ./tests/pg_ai_query_tests --gtest_output=xml:test_results.xml
echo "Unit tests passed!"
- name: Upload test results
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
if: always()
with:
name: test-results-${{ matrix.os }}-pg${{ matrix.pg_version }}
path: build_tests/test_results.xml
retention-days: 7
- name: Run extension tests
run: |
set -e # Fail on any error
# Install extension for testing
if [[ "${{ matrix.os }}" == "macos-latest" ]]; then
export PG_CONFIG=$(brew --prefix postgresql@${{ matrix.pg_version }})/bin/pg_config
export PATH="$(brew --prefix postgresql@${{ matrix.pg_version }})/bin:$PATH"
export PGDATA="/opt/homebrew/var/postgresql@${{ matrix.pg_version }}"
# Install into the correct Homebrew prefix
INSTALL_PREFIX=$(brew --prefix postgresql@${{ matrix.pg_version }})
sudo cmake --install build --prefix "$INSTALL_PREFIX"
# macOS: use psql from PATH
PSQL="psql"
else
# Ubuntu: Install to default system paths
sudo cmake --install build
# Ubuntu: use version-specific psql
PSQL="$PG_BIN/psql -p 5432"
fi
# Verify psql is available
$PSQL --version || echo "psql version check failed"
# Get paths from pg_config (use version-specific path for Ubuntu)
if [[ "${{ matrix.os }}" == "macos-latest" ]]; then
PG_CONFIG=${PG_CONFIG:-$(brew --prefix postgresql@${{ matrix.pg_version }})/bin/pg_config}
else
PG_CONFIG=/usr/lib/postgresql/${{ matrix.pg_version }}/bin/pg_config
fi
PG_PKGLIB=$($PG_CONFIG --pkglibdir)
PG_LIBDIR=$($PG_CONFIG --libdir)
PG_SHAREDIR=$($PG_CONFIG --sharedir)
echo "PostgreSQL pkglibdir: $PG_PKGLIB"
echo "PostgreSQL libdir: $PG_LIBDIR"
echo "PostgreSQL sharedir: $PG_SHAREDIR"
# Use correct extension based on OS and PostgreSQL version
if [[ "${{ matrix.os }}" == "macos-latest" ]]; then
# PostgreSQL 16+ on macOS uses .dylib, earlier versions use .so
if [[ "${{ matrix.pg_version }}" -ge 16 ]]; then
EXTENSION_PATH="$PG_PKGLIB/pg_ai_query.dylib"
else
EXTENSION_PATH="$PG_PKGLIB/pg_ai_query.so"
fi
else
EXTENSION_PATH="$PG_PKGLIB/pg_ai_query.so"
fi
echo "Checking for extension binary in pkglibdir:"
ls -la "$EXTENSION_PATH" || { echo "Extension binary not found in pkglibdir"; exit 1; }
# Test $libdir resolution
echo "Testing \$libdir resolution:"
$PSQL -d testdb -c "SHOW dynamic_library_path;" || echo "Could not check dynamic_library_path"
# Check control and SQL files
echo "Checking for control file:"
ls -la "$PG_SHAREDIR/extension/pg_ai_query.control" || echo "Control file not found"
echo "Checking for SQL file:"
ls -la "$PG_SHAREDIR/extension/pg_ai_query--1.0.sql" || echo "SQL file not found"
# Check linked libraries (macOS only)
if [[ "${{ matrix.os }}" == "macos-latest" ]]; then
echo "Checking linked libraries for: $EXTENSION_PATH"
otool -L "$EXTENSION_PATH" || echo "Could not check linked libraries"
else
echo "Checking linked libraries for: $EXTENSION_PATH"
ldd "$EXTENSION_PATH" || echo "Could not check linked libraries"
fi
# Basic functionality test
$PSQL -d testdb -c "CREATE EXTENSION IF NOT EXISTS pg_ai_query;" || { echo "CREATE EXTENSION failed"; exit 1; }
# Test basic functions exist
$PSQL -d testdb -c "\\df generate_query"
$PSQL -d testdb -c "\\df get_database_tables"
$PSQL -d testdb -c "\\df get_table_details"
# Test with sample data
$PSQL -d testdb -c "CREATE TABLE test_users (id SERIAL PRIMARY KEY, name VARCHAR(100));"
$PSQL -d testdb -c "INSERT INTO test_users (name) VALUES ('Test User');"
# Test schema discovery
$PSQL -d testdb -c "SELECT get_database_tables();"
$PSQL -d testdb -c "SELECT get_table_details('test_users');"
echo "Extension tests passed!"
- name: Run PostgreSQL test suite
run: |
# Run our SQL test suite
if [[ "${{ matrix.os }}" == "macos-latest" ]]; then
export PATH="$(brew --prefix postgresql@${{ matrix.pg_version }})/bin:$PATH"
export PGDATABASE=testdb
else
export PATH="$PG_BIN:$PATH"
export PGDATABASE=testdb
export PGPORT=5432
fi
echo "=== Running PostgreSQL Test Suite ==="
psql -d $PGDATABASE -f tests/sql/setup.sql -q 2>/dev/null || true
psql -d $PGDATABASE -f tests/sql/test_extension_functions.sql
psql -d $PGDATABASE -f tests/sql/teardown.sql -q 2>/dev/null || true
echo "PostgreSQL test suite passed!"
- name: Upload build artifacts
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
if: always()
with:
name: build-artifacts-${{ matrix.os }}-pg${{ matrix.pg_version }}
path: |
build/*.so
build/*.dylib
build/CMakeCache.txt
build/CMakeFiles/CMakeError.log
retention-days: 7
static-analysis:
name: Static Analysis
runs-on: ubuntu-24.04
steps:
- name: Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
submodules: recursive
- name: Install dependencies
run: |
# Install PostgreSQL from official APT repository
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
sudo apt-get update
sudo apt-get install -y \
build-essential \
cmake \
libssl-dev \
libcurl4-openssl-dev \
gettext \
libz-dev \
postgresql-14 \
postgresql-server-dev-14 \
cppcheck \
clang-tidy
- name: Configure CMake with static analysis
run: |
cmake -B build -DCMAKE_BUILD_TYPE=Debug \
-DPG_CONFIG=/usr/lib/postgresql/14/bin/pg_config \
-DCMAKE_CXX_CPPCHECK="cppcheck;--enable=all;--suppress=missingIncludeSystem" \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
- name: Run static analysis
run: |
cmake --build build --target all 2>&1 | tee static-analysis.log
- name: Run clang-tidy
run: |
find src -name "*.cpp" -o -name "*.hpp" | head -10 | \
xargs clang-tidy -p build --checks='-*,readability-*,performance-*,bugprone-*,modernize-*' \
2>&1 | tee clang-tidy.log || true
- name: Upload analysis results
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: static-analysis-results
path: |
static-analysis.log
clang-tidy.log
retention-days: 30
# Test the root Makefile build (uses PGXS) to catch LLVM/JIT related issues
# This catches issues like #29 where PGXS tries to build .bc files
makefile-build-test:
name: Makefile Build (PGXS)
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
pg_version: ["16", "17", "18"]
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
submodules: recursive
- name: Install PostgreSQL ${{ matrix.pg_version }} with LLVM support
run: |
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
sudo apt-get update
sudo apt-get install -y \
build-essential \
cmake \
libssl-dev \
libcurl4-openssl-dev \
pkg-config \
gettext \
libz-dev \
postgresql-${{ matrix.pg_version }} \
postgresql-server-dev-${{ matrix.pg_version }}
- name: Verify LLVM/JIT configuration
run: |
PG_CONFIG=/usr/lib/postgresql/${{ matrix.pg_version }}/bin/pg_config
echo "PostgreSQL version: $($PG_CONFIG --version)"
echo "LLVM support check:"
$PG_CONFIG --configure | grep -i llvm || echo "LLVM flags not in configure output"
- name: Test Makefile build (make)
run: |
export PATH="/usr/lib/postgresql/${{ matrix.pg_version }}/bin:$PATH"
echo "Testing 'make' command (uses PGXS)..."
make clean || true
make
echo "Makefile build succeeded!"
- name: Verify build output
run: |
ls -la pg_ai_query.so || ls -la build/pg_ai_query.so
echo "Build artifacts verified!"
- name: Test make clean removes extension file
run: |
export PATH="/usr/lib/postgresql/${{ matrix.pg_version }}/bin:$PATH"
echo "Verifying make clean removes pg_ai_query.so..."
test -f pg_ai_query.so || { echo "pg_ai_query.so not found before clean"; exit 1; }
make clean
if [ -f pg_ai_query.so ]; then
echo "ERROR: make clean did not remove pg_ai_query.so"
exit 1
fi
echo "make clean correctly removes extension file!"
- name: Test make install installs shared library
run: |
export PATH="/usr/lib/postgresql/${{ matrix.pg_version }}/bin:$PATH"
PG_PKGLIB=$(pg_config --pkglibdir)
echo "Rebuilding and testing make install..."
make
sudo make install
if [ ! -f "$PG_PKGLIB/pg_ai_query.so" ]; then
echo "ERROR: make install did not install pg_ai_query.so to $PG_PKGLIB"
ls -la "$PG_PKGLIB" | grep pg_ai || true
exit 1
fi
echo "make install correctly installs shared library to $PG_PKGLIB!"
security-scan:
name: Security Scan
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
submodules: recursive
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: "fs"
format: "sarif"
output: "trivy-results.sarif"
- name: Upload Trivy scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v4
if: always() && github.event_name != 'pull_request'
continue-on-error: true
with:
sarif_file: "trivy-results.sarif"
- name: Upload Trivy results as artifact (for PRs)
if: github.event_name == 'pull_request'
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: trivy-security-scan-results
path: "trivy-results.sarif"
retention-days: 7
- name: Check for secrets
uses: trufflesecurity/trufflehog@main
with:
path: ./
extra_args: --debug --only-verified