fix memory leak: pfree() text_to_cstring() results #249
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |