Skip to content

Upgrade CodeQL CLI dependency to v2.25.0 #267

Upgrade CodeQL CLI dependency to v2.25.0

Upgrade CodeQL CLI dependency to v2.25.0 #267

name: QL MCP Client Integration Tests
on:
push:
branches: [main]
paths:
- '.github/actions/setup-codeql-environment/action.yml'
- '.github/workflows/client-integration-tests.yml'
- '.codeql-version'
- '.node-version'
- 'client/**'
- 'server/**'
pull_request:
branches: [main]
paths:
- '.github/actions/setup-codeql-environment/action.yml'
- '.github/workflows/client-integration-tests.yml'
- '.codeql-version'
- '.node-version'
- 'client/**'
- 'server/**'
workflow_dispatch:
permissions:
contents: read
jobs:
integration-tests:
name: Integration Tests (${{ matrix.os }}, ${{ matrix.mcp-mode }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
mcp-mode: [http, stdio]
os: [ubuntu-latest, windows-latest]
env:
HTTP_HOST: 'localhost'
HTTP_PORT: '3000'
MCP_MODE: ${{ matrix.mcp-mode }}
TIMEOUT_SECONDS: '30'
URL_SCHEME: 'http'
steps:
- name: MCP Integration Tests - Checkout repository
uses: actions/checkout@v6
- name: MCP Integration Tests - Setup Node.js environment
uses: actions/setup-node@v6
with:
cache: 'npm'
node-version-file: '.node-version'
- name: MCP Integration Tests - Install OS dependencies (Ubuntu)
if: runner.os == 'Linux'
run: sudo apt-get install -y jq
- name: MCP Integration Tests - Install OS dependencies (Windows)
if: runner.os == 'Windows'
run: choco install jq -y
- name: MCP Integration Tests - Install node dependencies for client and server workspaces
run: npm ci --workspace=client && npm ci --workspace=server
- name: MCP Integration Tests - Setup CodeQL environment
uses: ./.github/actions/setup-codeql-environment
with:
install-language-runtimes: false
## Verify that the CodeQL CLI is spawnable from Node.js, not just from
## bash. On Windows, Node.js spawn()/execFile() require a real .exe
## binary on PATH, not a bash stub or .cmd wrapper. Fail fast here
## instead of waiting for integration tests to time out.
- name: MCP Integration Tests - Verify CodeQL CLI is spawnable from Node.js
shell: bash
run: |
node -e "
const { execFile } = require('child_process');
execFile('codeql', ['version', '--format=terse'], (err, stdout) => {
if (err) {
console.error('❌ CodeQL CLI is not spawnable from Node.js:', err.message);
console.error('This typically means codeql.exe is not on PATH (Windows).');
process.exit(1);
}
console.log('✅ CodeQL CLI is spawnable from Node.js, version:', stdout.trim());
});
"
## Install packs used in the integration tests.
- name: MCP Integration Tests - Install CodeQL packs
shell: bash
run: ./server/scripts/install-packs.sh
## Extract test databases used in the integration tests.
- name: MCP Integration Tests - Extract test databases
shell: bash
run: ./server/scripts/extract-test-databases.sh
## Configure npm to use bash for running scripts on Windows, since the
## integration test scripts are bash scripts that cmd.exe cannot execute.
- name: MCP Integration Tests - Configure npm script shell (Windows)
if: runner.os == 'Windows'
shell: bash
run: npm config set script-shell "$(which bash)"
## Run integration tests. This script builds the server bundle and runs tests.
## We do NOT use 'npm run build-and-test' as it runs query unit tests which
## have a dedicated workflow (query-unit-tests.yml).
- name: MCP Integration Tests - Run integration tests
shell: bash
run: npm run test:integration --workspace=client
- name: MCP Integration Tests - Stop the background MCP server process
if: always() && matrix.mcp-mode == 'http'
shell: bash
run: |
if [ -f server.pid ]; then
PID=$(cat server.pid)
echo "Stopping server with PID $PID"
if kill -0 "$PID" 2>/dev/null; then
kill "$PID" || true
sleep 2
# Force kill if still running
if kill -0 "$PID" 2>/dev/null; then
echo "Force killing server process"
kill -9 "$PID" || true
fi
else
echo "Server process was not running"
fi
rm -f server.pid
else
echo "No server.pid file found"
fi
# Clean up log files
if [ -f server.log ]; then
echo "Removing server.log"
rm -f server.log
fi
- name: MCP Integration Tests - Summary
shell: bash
run: |
echo "## Integration Tests Summary (${{ matrix.os }}, ${{ matrix.mcp-mode }})" >> $GITHUB_STEP_SUMMARY
echo "✅ MCP server integration tests passed on ${{ matrix.os }} with ${{ matrix.mcp-mode }} transport" >> $GITHUB_STEP_SUMMARY
codeql-path-tests:
name: CODEQL_PATH Tests (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [macos-latest, ubuntu-latest, windows-latest]
steps:
- name: CODEQL_PATH Tests - Checkout repository
uses: actions/checkout@v6
- name: CODEQL_PATH Tests - Setup Node.js
uses: actions/setup-node@v6
with:
cache: 'npm'
node-version-file: '.node-version'
- name: CODEQL_PATH Tests - Install server dependencies
run: npm ci --workspace=server
- name: CODEQL_PATH Tests - Build server bundle
run: npm run bundle -w server
- name: CODEQL_PATH Tests - Setup CodeQL environment
uses: ./.github/actions/setup-codeql-environment
with:
add-to-path: false
install-language-runtimes: false
## Locate the real CodeQL binary (not the gh-codeql bash stub).
## The stub delegates to `gh codeql` and works from bash, but Node.js
## execFile() on Windows cannot execute bash scripts — it needs a real
## .exe. We search the gh-codeql distribution directory for the binary.
- name: CODEQL_PATH Tests - Locate CodeQL binary
id: locate-codeql
shell: bash
run: |
if [[ "$RUNNER_OS" == "Windows" ]]; then
# The gh-codeql extension stores CodeQL distributions under
# %LOCALAPPDATA%\GitHub\gh-codeql on Windows (its own data dir),
# separate from the GitHub CLI extensions directory. Search there
# first, then fall back to the extensions dir and all LOCALAPPDATA.
LOCALAPPDATA_DIR="${LOCALAPPDATA:-$HOME/AppData/Local}"
CODEQL_BINARY=""
for search_dir in \
"${LOCALAPPDATA_DIR}/GitHub/gh-codeql" \
"${LOCALAPPDATA_DIR}/GitHub CLI/extensions/gh-codeql" \
"${LOCALAPPDATA_DIR}"; do
if [[ -d "$search_dir" ]]; then
CODEQL_BINARY=$(find "$search_dir" -maxdepth 10 \
-name "codeql.exe" -type f 2>/dev/null | head -1)
if [[ -n "$CODEQL_BINARY" ]]; then
break
fi
fi
done
# Convert MSYS path to Windows mixed-mode path for Node.js
if [[ -n "$CODEQL_BINARY" ]]; then
CODEQL_BINARY=$(cygpath -m "$CODEQL_BINARY")
fi
else
for search_dir in "$HOME/.local" "$HOME/Library"; do
if [[ -d "$search_dir" ]]; then
CODEQL_BINARY=$(find "$search_dir" -path "*gh-codeql*release*" -name "codeql" -type f 2>/dev/null | head -1)
if [[ -n "$CODEQL_BINARY" ]]; then
break
fi
fi
done
fi
if [[ -z "$CODEQL_BINARY" ]]; then
echo "::error::Could not locate CodeQL binary in gh-codeql distribution"
exit 1
fi
# Verify the binary works and reports the expected version
ACTUAL=$("$CODEQL_BINARY" version --format=terse 2>/dev/null)
EXPECTED=$(gh codeql version --format=terse 2>/dev/null)
if [[ "$ACTUAL" != "$EXPECTED" ]]; then
echo "::error::Binary version mismatch: got '$ACTUAL', expected '$EXPECTED'"
exit 1
fi
echo "✅ CodeQL binary verified: $CODEQL_BINARY (version $ACTUAL)"
echo "codeql-version=$ACTUAL" >> "$GITHUB_OUTPUT"
echo "codeql-binary=$CODEQL_BINARY" >> "$GITHUB_OUTPUT"
## Build a PATH that excludes every directory containing 'codeql'.
## This simulates an environment where the CodeQL CLI is not installed
## globally, forcing the server to rely solely on CODEQL_PATH.
- name: CODEQL_PATH Tests - Build clean PATH without CodeQL
shell: bash
run: |
CLEAN_PATH=""
IFS=':' read -ra PARTS <<< "$PATH"
for part in "${PARTS[@]}"; do
case "$part" in
*codeql*|*gh-codeql*) ;;
*)
CLEAN_PATH="${CLEAN_PATH:+$CLEAN_PATH:}$part"
;;
esac
done
# Verify codeql is NOT findable on the clean PATH
if PATH="$CLEAN_PATH" command -v codeql >/dev/null 2>&1; then
echo "::error::codeql is still discoverable after PATH cleanup"
exit 1
fi
echo "✅ codeql is not on the clean PATH"
echo "CLEAN_PATH=$CLEAN_PATH" >> "$GITHUB_ENV"
## Test 1: The server must fail early at startup when CODEQL_PATH points
## to a non-existent file and codeql is not on PATH.
- name: CODEQL_PATH Tests - Test 1 - Fail with invalid CODEQL_PATH
shell: bash
run: ./server/scripts/test-codeql-path-invalid.sh
## Test 2: The server must fail at startup when codeql is not on PATH
## and CODEQL_PATH is not set.
- name: CODEQL_PATH Tests - Test 2 - Fail when codeql not on PATH and CODEQL_PATH not set
shell: bash
run: ./server/scripts/test-codeql-path-missing.sh
## Test 3: The server must start without error when CODEQL_PATH points
## to a valid CodeQL binary, even though codeql is not on PATH.
- name: CODEQL_PATH Tests - Test 3 - Start with valid CODEQL_PATH
shell: bash
run: ./server/scripts/test-codeql-path-valid.sh "${{ steps.locate-codeql.outputs.codeql-binary }}"
- name: CODEQL_PATH Tests - Summary
shell: bash
run: |
echo "## CODEQL_PATH Tests (${{ matrix.os }})" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Test | Result |" >> $GITHUB_STEP_SUMMARY
echo "| ---- | ------ |" >> $GITHUB_STEP_SUMMARY
echo "| Invalid CODEQL_PATH causes startup failure | ✅ Pass |" >> $GITHUB_STEP_SUMMARY
echo "| Missing codeql (no PATH, no CODEQL_PATH) causes startup failure | ✅ Pass |" >> $GITHUB_STEP_SUMMARY
echo "| Valid CODEQL_PATH (no PATH) starts server | ✅ Pass |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Detail | Value |" >> $GITHUB_STEP_SUMMARY
echo "| ------ | ----- |" >> $GITHUB_STEP_SUMMARY
echo "| CodeQL Version | ${{ steps.locate-codeql.outputs.codeql-version }} |" >> $GITHUB_STEP_SUMMARY
echo "| CodeQL Binary | \`${{ steps.locate-codeql.outputs.codeql-binary }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| OS | ${{ matrix.os }} |" >> $GITHUB_STEP_SUMMARY