diff --git a/.github/instructions/server_ql_languages_tools.instructions.md b/.github/instructions/server_ql_languages_tools.instructions.md index e3e09c8..ee0ca9a 100644 --- a/.github/instructions/server_ql_languages_tools.instructions.md +++ b/.github/instructions/server_ql_languages_tools.instructions.md @@ -22,10 +22,13 @@ Each language directory follows a standardized structure that enables automatic - ALWAYS place query implementation files in `tools/src//` subdirectories. - ALWAYS place corresponding test files in `tools/test//` subdirectories. - ALWAYS include proper CodeQL query metadata using `@name`, `@description`, `@id`, `@kind`, and `@tags` annotations. +- ALWAYS create a `.md` query documentation file alongside every `.ql` query in `tools/src//` (e.g., `PrintAST.md` next to `PrintAST.ql`). This is enforced by the `query-documentation.test.ts` unit test. +- ALWAYS use the existing `server/ql/*/tools/src/PrintCFG/PrintCFG.md` files as the canonical style reference for `@kind graph` query documentation. These docs describe the structural output (nodes/edges) rather than flagging problems, so code examples should illustrate what structure the query visualizes — not whether code is compliant or non-compliant. - ALWAYS create `.qlref` files that reference the correct query path relative to the tools directory. - ALWAYS create `.expected` files with the expected output for each test case. -- ALWAYS implement test code source files that test both the query's ability to ignore `COMPLIANT` code patterns AND to detect `NON_COMPLIANT` code patterns. -- ALWAYS comment test cases as either `COMPLIANT` (i.e. query should not match) or `NON-COMPLIANT` (i.e. query should match). +- ALWAYS implement test code source files that test both the query's ability to ignore `COMPLIANT` code patterns AND to detect `NON_COMPLIANT` code patterns for detection-style queries (`@kind problem` / `@kind path-problem`). +- ALWAYS comment test cases as either `COMPLIANT` (i.e. query should not match) or `NON_COMPLIANT` (i.e. query should match) for detection-style queries. +- ALWAYS omit `COMPLIANT` and `NON_COMPLIANT` annotations from `@kind graph` query documentation and test code, because these queries produce structural output (ASTs, CFGs, call graphs) rather than detecting problems. - ALWAYS use the `server/scripts/install-packs.sh` script to install dependencies for CodeQL packs defined under the `server/ql/*/language/tools/` directories. - ALWAYS use explicit version numbers in `codeql-pack.yml` files; never use wildcards (`*`). - ALWAYS set `ql-mcp-*` pack versions to match the CodeQL CLI version from `.codeql-version` (without the `v` prefix). @@ -51,4 +54,5 @@ Each language directory follows a standardized structure that enables automatic - NEVER create `.qlref` files with incorrect paths or missing target queries. - NEVER mix different query purposes within a single query file. - NEVER omit required CodeQL query metadata annotations. +- NEVER omit query documentation (`.md`) for any query published in a `tools/src/` pack directory. - NEVER create test cases that don't actually exercise the query logic being tested. diff --git a/.github/workflows/build-and-test-extension.yml b/.github/workflows/build-and-test-extension.yml index b89688a..b93901b 100644 --- a/.github/workflows/build-and-test-extension.yml +++ b/.github/workflows/build-and-test-extension.yml @@ -69,7 +69,9 @@ jobs: - name: Verify VSIX packaging working-directory: extensions/vscode - run: npx @vscode/vsce package --no-dependencies --out codeql-development-mcp-server.vsix + run: | + VERSION=$(node -e "console.log(require('./package.json').version)") + npx @vscode/vsce package --no-dependencies --out "codeql-development-mcp-server-v${VERSION}.vsix" - name: Verify VSIX contents working-directory: extensions/vscode diff --git a/.github/workflows/release-codeql.yml b/.github/workflows/release-codeql.yml index 16a5706..fa8a342 100644 --- a/.github/workflows/release-codeql.yml +++ b/.github/workflows/release-codeql.yml @@ -81,13 +81,22 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | + RELEASE_NAME="${{ steps.version.outputs.release_name }}" LANGUAGES="actions cpp csharp go java javascript python ruby swift" + + # Prerelease versions (containing a hyphen) require --allow-prerelease + PRERELEASE_FLAG="" + if [[ "${RELEASE_NAME}" == *-* ]]; then + PRERELEASE_FLAG="--allow-prerelease" + echo "Detected prerelease version — using ${PRERELEASE_FLAG}" + fi + echo "Publishing CodeQL tool query packs..." for lang in ${LANGUAGES}; do PACK_DIR="server/ql/${lang}/tools/src" if [ -d "${PACK_DIR}" ]; then echo "📦 Publishing ${PACK_DIR}..." - codeql pack publish --threads=-1 -- "${PACK_DIR}" + codeql pack publish --threads=-1 ${PRERELEASE_FLAG} -- "${PACK_DIR}" echo "✅ Published ${lang} tool query pack" else echo "⚠️ Skipping ${lang}: ${PACK_DIR} not found" @@ -106,7 +115,8 @@ jobs: for lang in ${LANGUAGES}; do PACK_DIR="server/ql/${lang}/tools/src" if [ -d "${PACK_DIR}" ]; then - PACK_NAME="ql-mcp-${lang}-tools-src" + VERSION="${{ steps.version.outputs.version }}" + PACK_NAME="ql-mcp-${lang}-tools-src-${VERSION}" OUTPUT="dist-packs/${PACK_NAME}.tar.gz" echo "📦 Bundling ${PACK_DIR} -> ${OUTPUT}..." codeql pack bundle --threads=-1 --output="${OUTPUT}" -- "${PACK_DIR}" diff --git a/.github/workflows/release-tag.yml b/.github/workflows/release-tag.yml index 6b97716..de530fe 100644 --- a/.github/workflows/release-tag.yml +++ b/.github/workflows/release-tag.yml @@ -63,11 +63,27 @@ jobs: id: check-tag run: | TAG="${{ steps.version.outputs.version }}" + RELEASE_NAME="${{ steps.version.outputs.release_name }}" if git rev-parse "refs/tags/${TAG}" >/dev/null 2>&1; then TAG_SHA=$(git rev-parse "refs/tags/${TAG}^{commit}" 2>/dev/null || git rev-parse "refs/tags/${TAG}") - echo "tag_exists=true" >> $GITHUB_OUTPUT - echo "tag_sha=${TAG_SHA}" >> $GITHUB_OUTPUT echo "ℹ️ Tag ${TAG} already exists at commit ${TAG_SHA:0:8}" + + # Verify version-bearing files at the tagged commit match the release + TAG_SERVER_VERSION=$(git show "${TAG_SHA}:server/package.json" \ + | grep -m1 '"version"' \ + | sed 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/') + if [[ "${TAG_SERVER_VERSION}" == "${RELEASE_NAME}" ]]; then + echo "tag_exists=true" >> $GITHUB_OUTPUT + echo "tag_sha=${TAG_SHA}" >> $GITHUB_OUTPUT + echo "✅ Existing tag ${TAG} has correct version (${RELEASE_NAME})" + else + echo "⚠️ Version mismatch at tag ${TAG}: found ${TAG_SERVER_VERSION}, expected ${RELEASE_NAME}" + echo " Removing stale tag to recreate with correct versions..." + git tag -d "${TAG}" 2>/dev/null || true + git push origin ":refs/tags/${TAG}" 2>/dev/null || true + echo "tag_exists=false" >> $GITHUB_OUTPUT + echo "ℹ️ Stale tag ${TAG} removed — will recreate with updated versions" + fi else echo "tag_exists=false" >> $GITHUB_OUTPUT echo "ℹ️ Tag ${TAG} does not exist yet" @@ -128,8 +144,8 @@ jobs: # Stage version-bearing files and lockfile changes git add -A # Ensure CodeQL-generated artifacts are not staged for commit - git restore --staged .codeql || true - git restore --staged '*.qlx' || true + git restore --staged .codeql 2>/dev/null || true + git restore --staged '*.qlx' 2>/dev/null || true # Check if there are changes to commit if git diff --cached --quiet; then diff --git a/.github/workflows/release-vsix.yml b/.github/workflows/release-vsix.yml index 15950a0..1231ca1 100644 --- a/.github/workflows/release-vsix.yml +++ b/.github/workflows/release-vsix.yml @@ -15,7 +15,7 @@ on: description: 'The full version string with "v" prefix (e.g., vX.Y.Z)' value: ${{ jobs.publish-vsix.outputs.version }} vsix_name: - description: 'The VSIX filename (e.g., codeql-development-mcp-server.vsix)' + description: 'The VSIX filename (e.g., codeql-development-mcp-server-vX.Y.Z.vsix)' value: ${{ jobs.publish-vsix.outputs.vsix_name }} # Note: This workflow is called exclusively via workflow_call from release.yml. @@ -85,7 +85,8 @@ jobs: id: package working-directory: extensions/vscode run: | - VSIX_NAME="codeql-development-mcp-server.vsix" + VERSION="${{ steps.version.outputs.version }}" + VSIX_NAME="codeql-development-mcp-server-${VERSION}.vsix" npx @vscode/vsce package --no-dependencies --out "${VSIX_NAME}" echo "vsix_name=${VSIX_NAME}" >> $GITHUB_OUTPUT echo "✅ Packaged ${VSIX_NAME}" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1a5fb15..0a8f6e4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -29,6 +29,10 @@ on: permissions: contents: read +concurrency: + group: release-${{ github.event.inputs.version || github.ref_name }} + cancel-in-progress: true + jobs: # ───────────────────────────────────────────────────────────────────────────── # Step 1: Determine the release version @@ -239,7 +243,7 @@ jobs: files: | codeql-development-mcp-server-${{ needs.resolve-version.outputs.version }}.tar.gz dist-packs/*.tar.gz - dist-vsix/codeql-development-mcp-server.vsix + dist-vsix/codeql-development-mcp-server-${{ needs.resolve-version.outputs.version }}.vsix generate_release_notes: true tag_name: ${{ needs.resolve-version.outputs.version }} diff --git a/.gitignore b/.gitignore index c2b3b50..213affd 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ codeql-development-mcp-server.code-workspace *.swo *.tgz *.tar.gz +*.vsix *~ .vscode/mcp.json diff --git a/client/package.json b/client/package.json index d365715..e72fe28 100644 --- a/client/package.json +++ b/client/package.json @@ -1,6 +1,6 @@ { "name": "codeql-development-mcp-server_client", - "version": "2.24.2", + "version": "2.24.2-rc3", "description": "MCP client for integration testing of the CodeQL development MCP server", "main": "src/ql-mcp-client.js", "type": "module", diff --git a/docs/getting-started.md b/docs/getting-started.md index 550f91b..5dd4625 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -47,7 +47,7 @@ npx -y codeql-development-mcp-server ### From GitHub Releases 1. Download the latest release from [Releases](https://github.com/advanced-security/codeql-development-mcp-server/releases) -2. Extract: `tar -xzf codeql-development-mcp-server-vX.X.X.tar.gz -C /path/to/destination` +2. Extract: `tar -xzf codeql-development-mcp-server-vX.Y.Z.tar.gz -C /path/to/destination` ### From Source diff --git a/docs/vscode/extension.md b/docs/vscode/extension.md index f8ae7df..a9aaa78 100644 --- a/docs/vscode/extension.md +++ b/docs/vscode/extension.md @@ -17,12 +17,12 @@ to do by hand. ### From `.vsix` (GitHub Releases) -Download `codeql-development-mcp-server.vsix` from the latest +Download `codeql-development-mcp-server-vX.Y.Z.vsix` from the latest [GitHub Release](https://github.com/advanced-security/codeql-development-mcp-server/releases), then install: ```bash -code --install-extension codeql-development-mcp-server.vsix +code --install-extension codeql-development-mcp-server-vX.Y.Z.vsix ``` Or in VS Code: **Extensions** sidebar → `⋯` menu → **Install from VSIX…** → select the file. @@ -40,7 +40,7 @@ From the repository root: ```bash npm run package:vsix -code --install-extension extensions/vscode/codeql-development-mcp-server.vsix +code --install-extension extensions/vscode/codeql-development-mcp-server-vX.Y.Z.vsix ``` The extension requires the [CodeQL extension](https://marketplace.visualstudio.com/items?itemName=GitHub.vscode-codeql) (`GitHub.vscode-codeql`) and will prompt you to install it if missing. diff --git a/extensions/vscode/README.md b/extensions/vscode/README.md index bac14f8..4839071 100644 --- a/extensions/vscode/README.md +++ b/extensions/vscode/README.md @@ -13,7 +13,7 @@ A VS Code extension that automatically installs, configures, and manages the [Co ### From `.vsix` ```bash -code --install-extension codeql-development-mcp-server.vsix +code --install-extension codeql-development-mcp-server-vX.Y.Z.vsix ``` Or in VS Code: **Extensions** sidebar → `⋯` menu → **Install from VSIX…** → select the file. @@ -23,7 +23,7 @@ Or in VS Code: **Extensions** sidebar → `⋯` menu → **Install from VSIX…* ```bash cd extensions/vscode npm run package -code --install-extension codeql-development-mcp-server.vsix +code --install-extension codeql-development-mcp-server-vX.Y.Z.vsix ``` ## What It Does diff --git a/extensions/vscode/package.json b/extensions/vscode/package.json index ae8a266..54b8716 100644 --- a/extensions/vscode/package.json +++ b/extensions/vscode/package.json @@ -2,7 +2,7 @@ "name": "vscode-codeql-development-mcp-server", "displayName": "CodeQL Development MCP Server", "description": "LLM-assisted development of CodeQL queries, libraries, and tests via #ql-mcp prompts, resources, and tools.", - "version": "2.24.2", + "version": "2.24.2-rc3", "publisher": "advanced-security", "license": "SEE LICENSE IN LICENSE", "icon": "media/codeql-icon.png", @@ -140,7 +140,7 @@ "clean": "rm -rf dist server *.vsix", "lint": "eslint src/ test/", "lint:fix": "eslint src/ test/ --fix", - "package": "vsce package --no-dependencies --out codeql-development-mcp-server.vsix", + "package": "vsce package --no-dependencies --out codeql-development-mcp-server-v$(node -e 'process.stdout.write(require(`./package.json`).version)').vsix", "test": "npm run test:coverage && npm run test:integration", "test:coverage": "vitest --run --coverage", "test:integration": "vscode-test", diff --git a/extensions/vscode/src/extension.ts b/extensions/vscode/src/extension.ts index f51db90..8755232 100644 --- a/extensions/vscode/src/extension.ts +++ b/extensions/vscode/src/extension.ts @@ -172,12 +172,7 @@ export async function activate( // Run in background — don't block activation void (async () => { try { - const freshInstall = await serverManager.ensureInstalled(); - if (freshInstall) { - logger.info('Fresh npm install completed — running CodeQL pack setup...'); - } else { - logger.info('npm package already present — checking CodeQL packs...'); - } + await serverManager.ensureInstalled(); await packInstaller.installAll(); mcpProvider.fireDidChange(); logger.info('✅ MCP server setup complete. Server is ready to be started.'); diff --git a/extensions/vscode/src/server/pack-installer.ts b/extensions/vscode/src/server/pack-installer.ts index 37445a9..bf4f48d 100644 --- a/extensions/vscode/src/server/pack-installer.ts +++ b/extensions/vscode/src/server/pack-installer.ts @@ -16,13 +16,19 @@ export interface PackInstallOptions { /** * Installs CodeQL pack dependencies for the bundled tool query packs - * shipped with the `codeql-development-mcp-server` npm package. + * shipped inside the VSIX (or, as fallback, in the locally-installed + * `codeql-development-mcp-server` npm package). * - * The npm package bundles the qlpack source files (`.ql` + lock files), - * but their CodeQL library dependencies (e.g. `codeql/javascript-all`) - * must be fetched from GHCR via `codeql pack install`. This class - * automates the `codeql-development-mcp-server-setup-packs` step - * documented in the getting-started guide. + * The VSIX bundles the qlpack source files (`.ql` + lock files) at + * `/server/ql//tools/src/`, and the npm install + * mirrors them at `globalStorage/mcp-server/node_modules/.../ql/...`. + * The bundled copy is always preferred so that the packs used by + * `codeql pack install` match the server code running from the VSIX. + * + * CodeQL library dependencies (e.g. `codeql/javascript-all`) must be + * fetched from GHCR via `codeql pack install`. This class automates + * the `codeql-development-mcp-server-setup-packs` step documented in + * the getting-started guide. */ export class PackInstaller extends DisposableObject { static readonly SUPPORTED_LANGUAGES = [ @@ -46,13 +52,25 @@ export class PackInstaller extends DisposableObject { } /** - * Get the qlpack source directories for all languages under the - * locally installed npm package. + * Get the root directory for qlpack resolution. + * + * Prefers the bundled `server/` directory inside the VSIX so that the + * packs installed match the server version. Falls back to the + * npm-installed package root in `globalStorage` (for local dev or when + * the VSIX bundle is missing). + */ + private getQlpackRoot(): string { + return this.serverManager.getBundledQlRoot() + ?? this.serverManager.getPackageRoot(); + } + + /** + * Get the qlpack source directories for all languages. */ getQlpackPaths(): string[] { - const packageRoot = this.serverManager.getPackageRoot(); + const root = this.getQlpackRoot(); return PackInstaller.SUPPORTED_LANGUAGES.map((lang) => - join(packageRoot, 'ql', lang, 'tools', 'src'), + join(root, 'ql', lang, 'tools', 'src'), ); } @@ -69,12 +87,12 @@ export class PackInstaller extends DisposableObject { return; } - const packageRoot = this.serverManager.getPackageRoot(); + const qlRoot = this.getQlpackRoot(); const languages = options?.languages ?? [...PackInstaller.SUPPORTED_LANGUAGES]; for (const lang of languages) { - const packDir = join(packageRoot, 'ql', lang, 'tools', 'src'); + const packDir = join(qlRoot, 'ql', lang, 'tools', 'src'); // Check if the pack directory exists try { diff --git a/extensions/vscode/src/server/server-manager.ts b/extensions/vscode/src/server/server-manager.ts index 1ced2c8..9f394b9 100644 --- a/extensions/vscode/src/server/server-manager.ts +++ b/extensions/vscode/src/server/server-manager.ts @@ -1,7 +1,7 @@ import * as vscode from 'vscode'; import { execFile } from 'child_process'; import { access, readFile, mkdir } from 'fs/promises'; -import { accessSync, constants } from 'fs'; +import { accessSync, constants, readFileSync } from 'fs'; import { join } from 'path'; import { DisposableObject } from '../common/disposable'; import type { Logger } from '../common/logger'; @@ -24,18 +24,18 @@ export interface InstallOptions { } /** - * Manages the local npm installation of `codeql-development-mcp-server` - * into the extension's global storage directory. + * Manages the MCP server lifecycle for the VS Code extension. * - * The local install serves two purposes: - * 1. Provides the qlpack source files so PackInstaller can run - * `codeql pack install` to fetch their CodeQL library dependencies. - * 2. Provides a fallback entry point if the bundled server is missing. + * When the extension is installed from a VSIX, the `vscode:prepublish` + * step bundles `server/dist/`, `server/ql/`, and `server/package.json` + * inside the extension root. In that case no npm install is needed — + * the VSIX is fully self-contained. * - * The MCP server is launched from the **bundled** copy inside the VSIX - * (`server/dist/codeql-development-mcp-server.js`) so the extension is - * fully self-contained. Override via `codeql-mcp.serverCommand` / - * `codeql-mcp.serverArgs` settings for local development. + * A local npm install into `globalStorage` is performed **only** as a + * fallback when the bundled server is missing (e.g. running from the + * Extension Development Host without a prepublish build). Override via + * `codeql-mcp.serverCommand` / `codeql-mcp.serverArgs` settings for + * local development. */ export class ServerManager extends DisposableObject { private readonly storageRoot: string; @@ -90,19 +90,64 @@ export class ServerManager extends DisposableObject { } /** - * Ensure the npm package is installed locally. - * Returns `true` if a fresh install was performed. + * Get the extension's own version from its packageJSON. + * + * Reads `package.json` from the extension root (`context.extensionUri`) + * so that this works in all environments (VSIX, Extension Development + * Host, and tests) without relying on `vscode.extensions.getExtension`. + * + * This is the version baked into the VSIX and is used to determine + * whether the locally installed npm package is still up-to-date. + */ + getExtensionVersion(): string { + try { + const pkgPath = join(this.context.extensionUri.fsPath, 'package.json'); + const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')) as { version?: string }; + return pkg.version ?? 'unknown'; + } catch { + return 'unknown'; + } + } + + /** + * Ensure the npm package is available locally. + * + * When the VSIX bundle is present (the normal installed case), no npm + * install is needed — the bundle already ships `server/dist/`, + * `server/ql/`, and `server/package.json`. Returns `false` immediately. + * + * When the bundle is missing (Extension Development Host without a + * prepublish build), falls back to npm-installing the package into + * `globalStorage`. Returns `true` if a fresh install was performed. */ async ensureInstalled(): Promise { + // VSIX bundle or monorepo server is present — no npm install required. + if (this.getBundledQlRoot()) { + this.logger.info( + `Using bundled server (v${this.getExtensionVersion()}). ` + + 'No npm install required.', + ); + return false; + } + + // Fallback: no bundle — install via npm. + this.logger.info( + 'Bundled server not found — falling back to npm install...', + ); const config = vscode.workspace.getConfiguration('codeql-mcp'); const targetVersion = config.get('serverVersion', 'latest'); if (await this.isInstalled()) { const current = await this.getInstalledVersion(); - if (targetVersion === 'latest' || current === targetVersion) { + const effectiveTarget = + targetVersion === 'latest' ? this.getExtensionVersion() : targetVersion; + if (current === effectiveTarget) { this.logger.info(`MCP server package already installed (v${current}).`); return false; } + this.logger.info( + `Installed npm package (v${current}) differs from target (v${effectiveTarget}) — upgrading...`, + ); } await this.install({ version: targetVersion }); @@ -128,6 +173,36 @@ export class ServerManager extends DisposableObject { // Server launch configuration (for McpProvider) // --------------------------------------------------------------------------- + /** + * Root of the `server/` directory, checked in two locations: + * + * 1. **VSIX layout**: `/server/` (created by `vscode:prepublish`) + * — the extension is self-contained, no npm install required. + * 2. **Monorepo dev layout**: `/../../server/` — used when + * running from the Extension Development Host without a prepublish build. + * + * Returns the first location whose `server/package.json` is readable, or + * `undefined` if neither location exists. + */ + getBundledQlRoot(): string | undefined { + const extensionRoot = this.context.extensionUri.fsPath; + const candidate = join(extensionRoot, 'server'); + try { + accessSync(join(candidate, 'package.json'), constants.R_OK); + return candidate; + } catch { + // Not in VSIX layout — check monorepo + } + + const monorepo = join(extensionRoot, '..', '..', 'server'); + try { + accessSync(join(monorepo, 'package.json'), constants.R_OK); + return monorepo; + } catch { + return undefined; + } + } + /** * Absolute path to the MCP server entry point. * diff --git a/extensions/vscode/test/server/pack-installer.test.ts b/extensions/vscode/test/server/pack-installer.test.ts index ef803d1..ef51cd1 100644 --- a/extensions/vscode/test/server/pack-installer.test.ts +++ b/extensions/vscode/test/server/pack-installer.test.ts @@ -22,8 +22,9 @@ function createMockCliResolver() { } as any; } -function createMockServerManager() { +function createMockServerManager(bundledQlRoot?: string) { return { + getBundledQlRoot: vi.fn().mockReturnValue(bundledQlRoot ?? undefined), getPackageRoot: vi.fn().mockReturnValue('/mock/global-storage/mcp-server/node_modules/codeql-development-mcp-server'), getInstallDir: vi.fn().mockReturnValue('/mock/global-storage/mcp-server'), getCommand: vi.fn().mockReturnValue('npx'), @@ -70,7 +71,7 @@ describe('PackInstaller', () => { expect(languages).toHaveLength(9); }); - it('should resolve qlpack paths under the package root', () => { + it('should resolve qlpack paths under the npm package root when no bundle', () => { const paths = installer.getQlpackPaths(); expect(paths).toHaveLength(9); for (const p of paths) { @@ -79,6 +80,23 @@ describe('PackInstaller', () => { } }); + it('should prefer bundled ql root when VSIX bundle exists', () => { + const bundledManager = createMockServerManager('/mock/extension/server'); + const bundledInstaller = new PackInstaller( + cliResolver, + bundledManager, + logger, + ); + const paths = bundledInstaller.getQlpackPaths(); + expect(paths).toHaveLength(9); + for (const p of paths) { + expect(p).toMatch(/^\/mock\/extension\/server\/ql\//); + expect(p).toContain('/tools/src'); + } + // Should NOT have used npm package root + expect(bundledManager.getPackageRoot).not.toHaveBeenCalled(); + }); + it('should skip installation when CLI is not found', async () => { cliResolver.resolve.mockResolvedValue(undefined); diff --git a/extensions/vscode/test/server/server-manager.test.ts b/extensions/vscode/test/server/server-manager.test.ts index 999e2fa..8d2c957 100644 --- a/extensions/vscode/test/server/server-manager.test.ts +++ b/extensions/vscode/test/server/server-manager.test.ts @@ -13,17 +13,21 @@ vi.mock('fs/promises', () => ({ vi.mock('fs', () => ({ accessSync: vi.fn(), + readFileSync: vi.fn(), constants: { R_OK: 4 }, })); import { execFile } from 'child_process'; import { access, readFile } from 'fs/promises'; -import { accessSync } from 'fs'; +import { accessSync, readFileSync } from 'fs'; -function createMockContext() { +function createMockContext(extensionVersion = '2.24.2') { return { extensionUri: { fsPath: '/mock/extension' }, globalStorageUri: { fsPath: '/mock/global-storage' }, + extension: { + packageJSON: { version: extensionVersion }, + }, globalState: { get: vi.fn(), update: vi.fn().mockResolvedValue(undefined), @@ -172,14 +176,105 @@ describe('ServerManager', () => { expect(version).toBeUndefined(); }); - it('should skip install in ensureInstalled when already current', async () => { - vi.mocked(access).mockResolvedValue(undefined); - vi.mocked(readFile).mockResolvedValue(JSON.stringify({ version: '2.24.1' })); + it('should return extension version from context', () => { + vi.mocked(readFileSync).mockReturnValue(JSON.stringify({ version: '2.24.2' })); + expect(manager.getExtensionVersion()).toBe('2.24.2'); + }); + + describe('getBundledQlRoot', () => { + it('should return VSIX server/ path when bundle exists', () => { + vi.mocked(accessSync).mockImplementation(() => undefined); + expect(manager.getBundledQlRoot()).toBe('/mock/extension/server'); + }); + + it('should fall back to monorepo server/ when VSIX bundle is missing', () => { + let callCount = 0; + vi.mocked(accessSync).mockImplementation(() => { + callCount++; + if (callCount === 1) throw new Error('ENOENT'); + return undefined; + }); + const root = manager.getBundledQlRoot(); + expect(root).toContain('server'); + }); + + it('should return undefined when no bundle exists', () => { + vi.mocked(accessSync).mockImplementation(() => { throw new Error('ENOENT'); }); + expect(manager.getBundledQlRoot()).toBeUndefined(); + }); + }); - const installed = await manager.ensureInstalled(); + describe('ensureInstalled', () => { + it('should skip npm install when VSIX bundle is present', async () => { + // Bundle exists + vi.mocked(accessSync).mockImplementation(() => undefined); - expect(installed).toBe(false); // No fresh install - expect(execFile).not.toHaveBeenCalled(); + const installed = await manager.ensureInstalled(); + + expect(installed).toBe(false); + expect(execFile).not.toHaveBeenCalled(); + expect(logger.info).toHaveBeenCalledWith( + expect.stringContaining('bundled server'), + ); + }); + + it('should npm install when bundle is missing and nothing installed', async () => { + // No bundle + vi.mocked(accessSync).mockImplementation(() => { throw new Error('ENOENT'); }); + // Not installed + vi.mocked(access).mockRejectedValue(new Error('ENOENT')); + // npm succeeds + vi.mocked(execFile).mockImplementation( + (_cmd: any, _args: any, _opts: any, callback: any) => { + const cb = typeof _opts === 'function' ? _opts : callback; + cb(null, '', ''); + return {} as any; + }, + ); + + const installed = await manager.ensureInstalled(); + + expect(installed).toBe(true); + expect(execFile).toHaveBeenCalled(); + }); + + it('should skip npm install when bundle is missing but matching version installed', async () => { + // No bundle + vi.mocked(accessSync).mockImplementation(() => { throw new Error('ENOENT'); }); + // Extension version from package.json + vi.mocked(readFileSync).mockReturnValue(JSON.stringify({ version: '2.24.2' })); + // Already installed with matching version + vi.mocked(access).mockResolvedValue(undefined); + vi.mocked(readFile).mockResolvedValue(JSON.stringify({ version: '2.24.2' })); + + const installed = await manager.ensureInstalled(); + + expect(installed).toBe(false); + expect(execFile).not.toHaveBeenCalled(); + }); + + it('should upgrade npm install when bundle is missing and version differs', async () => { + // No bundle + vi.mocked(accessSync).mockImplementation(() => { throw new Error('ENOENT'); }); + // Old version installed + vi.mocked(access).mockResolvedValue(undefined); + vi.mocked(readFile).mockResolvedValue(JSON.stringify({ version: '2.24.1' })); + // npm succeeds + vi.mocked(execFile).mockImplementation( + (_cmd: any, _args: any, _opts: any, callback: any) => { + const cb = typeof _opts === 'function' ? _opts : callback; + cb(null, '', ''); + return {} as any; + }, + ); + + const installed = await manager.ensureInstalled(); + + expect(installed).toBe(true); + expect(logger.info).toHaveBeenCalledWith( + expect.stringContaining('differs from target'), + ); + }); }); it('should return undefined version when using latest', () => { diff --git a/package-lock.json b/package-lock.json index 97bd256..3cbe6f4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "codeql-development-mcp-server_repo", - "version": "2.24.2", + "version": "2.24.2-rc3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "codeql-development-mcp-server_repo", - "version": "2.24.2", + "version": "2.24.2-rc3", "license": "SEE LICENSE IN LICENSE", "workspaces": [ "client", @@ -28,7 +28,7 @@ }, "client": { "name": "codeql-development-mcp-server_client", - "version": "2.24.2", + "version": "2.24.2-rc3", "license": "SEE LICENSE IN LICENSE", "dependencies": { "@modelcontextprotocol/sdk": "^1.26.0", @@ -52,7 +52,7 @@ }, "extensions/vscode": { "name": "vscode-codeql-development-mcp-server", - "version": "2.24.2", + "version": "2.24.2-rc3", "license": "SEE LICENSE IN LICENSE", "devDependencies": { "@eslint/js": "^10.0.1", @@ -9540,7 +9540,7 @@ }, "server": { "name": "codeql-development-mcp-server", - "version": "2.24.2", + "version": "2.24.2-rc3", "license": "SEE LICENSE IN LICENSE", "dependencies": { "@modelcontextprotocol/sdk": "^1.26.0", diff --git a/package.json b/package.json index 6fb6f6e..8c87760 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codeql-development-mcp-server_repo", - "version": "2.24.2", + "version": "2.24.2-rc3", "description": "An MCP server supporting LLM requests for CodeQL development tools and resources.", "private": true, "type": "module", diff --git a/server/package.json b/server/package.json index a64e495..66e6226 100644 --- a/server/package.json +++ b/server/package.json @@ -1,6 +1,6 @@ { "name": "codeql-development-mcp-server", - "version": "2.24.2", + "version": "2.24.2-rc3", "description": "An MCP server supporting LLM requests for CodeQL development tools and resources.", "main": "dist/codeql-development-mcp-server.js", "type": "module", diff --git a/server/ql/actions/tools/src/PrintAST/PrintAST.md b/server/ql/actions/tools/src/PrintAST/PrintAST.md new file mode 100644 index 0000000..952cf46 --- /dev/null +++ b/server/ql/actions/tools/src/PrintAST/PrintAST.md @@ -0,0 +1,53 @@ +# Print AST for GitHub Actions + +Outputs a representation of the Abstract Syntax Tree (AST) for GitHub Actions workflows and composite actions. + +## Overview + +The Abstract Syntax Tree is a hierarchical representation of source code structure. Each node represents a syntactic construct (job, step, expression, etc.) and edges represent parent-child containment relationships. + +This query produces the full AST for specified GitHub Actions YAML files, which is useful for understanding workflow structure, inspecting how the CodeQL extractor parses action definitions, and debugging query logic that operates on AST nodes. + +## Use Cases + +This query is primarily used for: + +- Inspecting how CodeQL represents workflow structure +- Debugging queries that match on AST node types +- Understanding parent-child relationships between jobs, steps, and expressions +- Verifying extractor behavior for composite actions and reusable workflows +- IDE integration for syntax tree visualization + +## Example + +The following GitHub Actions workflow demonstrates AST structure through jobs and steps: + +```yaml +name: Example Workflow +on: [push] +jobs: + build: # Job node in AST + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 # Step node in AST + - name: Build + run: make build # Run step with expression +``` + +In the resulting AST: + +- The workflow root contains job definitions as children +- Each job contains step nodes +- `uses` and `run` steps produce distinct AST node types + +## Output Format + +The query produces a graph via the `PrintAstConfiguration` library: + +- `nodes`: Each AST node with its type, label, and properties +- `edges`: Parent-child relationships forming the syntax tree + +## References + +- [GitHub Actions Workflow Syntax](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions) +- [CodeQL Abstract Syntax Trees](https://codeql.github.com/docs/writing-codeql-queries/abstract-syntax-tree/) diff --git a/server/ql/actions/tools/src/PrintCFG/PrintCFG.md b/server/ql/actions/tools/src/PrintCFG/PrintCFG.md index 38b2e5b..37c7ef2 100644 --- a/server/ql/actions/tools/src/PrintCFG/PrintCFG.md +++ b/server/ql/actions/tools/src/PrintCFG/PrintCFG.md @@ -26,11 +26,11 @@ The following GitHub Actions workflow demonstrates control flow through jobs and name: Example Workflow on: [push] jobs: - test: # COMPLIANT - Job creates CFG node + test: # Job creates CFG node runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 # COMPLIANT - Step creates CFG node - - name: Run tests # COMPLIANT - Steps execute sequentially + - uses: actions/checkout@v2 # Step creates CFG node + - name: Run tests # Steps execute sequentially run: echo "Testing" ``` diff --git a/server/ql/actions/tools/src/codeql-pack.yml b/server/ql/actions/tools/src/codeql-pack.yml index 735827d..564214d 100644 --- a/server/ql/actions/tools/src/codeql-pack.yml +++ b/server/ql/actions/tools/src/codeql-pack.yml @@ -1,5 +1,5 @@ name: advanced-security/ql-mcp-actions-tools-src -version: 2.24.2 +version: 2.24.2-rc3 description: 'Queries for codeql-development-mcp-server tools for actions language' library: false dependencies: diff --git a/server/ql/actions/tools/test/codeql-pack.yml b/server/ql/actions/tools/test/codeql-pack.yml index e8c4de0..e2e4771 100644 --- a/server/ql/actions/tools/test/codeql-pack.yml +++ b/server/ql/actions/tools/test/codeql-pack.yml @@ -1,5 +1,5 @@ name: advanced-security/ql-mcp-actions-tools-test -version: 2.24.2 +version: 2.24.2-rc3 dependencies: advanced-security/ql-mcp-actions-tools-src: ${workspace} extractor: actions diff --git a/server/ql/cpp/tools/src/CallGraphFrom/CallGraphFrom.md b/server/ql/cpp/tools/src/CallGraphFrom/CallGraphFrom.md new file mode 100644 index 0000000..3a8dbe6 --- /dev/null +++ b/server/ql/cpp/tools/src/CallGraphFrom/CallGraphFrom.md @@ -0,0 +1,44 @@ +# CallGraphFrom for C++ + +Displays calls made from a specified function, showing the call graph outbound from the source function. + +## Overview + +This query identifies all function calls made within the body of a named function, producing an outbound call graph. Given a source function name, it reports each call site and the callee, which is useful for understanding function dependencies and call chains. + +The query accepts function names via an external predicate (`sourceFunction`) and supports both simple and qualified name matching. + +## Use Cases + +This query is primarily used for: + +- Mapping outbound dependencies of a specific function +- Understanding what a function calls and in what order +- Analyzing call chains for refactoring or security review + +## Example + +The following C++ code demonstrates outbound calls from `sourceFunc`: + +```cpp +void helper1() {} +void helper2() { helper1(); } + +void sourceFunc() { // Source function for analysis + helper1(); + helper2(); +} +``` + +Running with `sourceFunction = "sourceFunc"` produces results showing each call site with the message pattern ``Call from `sourceFunc` to `helper1``. + +## Output Format + +The query is a `@kind problem` query producing rows of: + +- ``select call, "Call from `source` to `callee`"`` + +## References + +- [C++ Functions](https://en.cppreference.com/w/cpp/language/functions) +- [CodeQL Call Graph Analysis](https://codeql.github.com/docs/writing-codeql-queries/about-data-flow-analysis/) diff --git a/server/ql/cpp/tools/src/CallGraphTo/CallGraphTo.md b/server/ql/cpp/tools/src/CallGraphTo/CallGraphTo.md new file mode 100644 index 0000000..1cb1346 --- /dev/null +++ b/server/ql/cpp/tools/src/CallGraphTo/CallGraphTo.md @@ -0,0 +1,41 @@ +# CallGraphTo for C++ + +Displays calls made to a specified function, showing the call graph inbound to the target function. + +## Overview + +This query identifies all call sites that invoke a named function, producing an inbound call graph. Given a target function name, it reports each caller and call location, which is useful for understanding how a function is used across the codebase. + +The query accepts function names via an external predicate (`targetFunction`) and supports both simple and qualified name matching. + +## Use Cases + +This query is primarily used for: + +- Finding all callers of a specific function +- Impact analysis before modifying a function signature +- Understanding usage patterns and entry points + +## Example + +The following C++ code demonstrates inbound calls to `targetFunc`: + +```cpp +void targetFunc() {} // Target function for analysis + +void caller1() { targetFunc(); } +void caller2() { targetFunc(); } +``` + +Running with `targetFunction = "targetFunc"` produces results showing each call site with the message pattern ``Call to `targetFunc` from `caller1``. + +## Output Format + +The query is a `@kind problem` query producing rows of: + +- ``select call, "Call to `target` from `caller`"`` + +## References + +- [C++ Functions](https://en.cppreference.com/w/cpp/language/functions) +- [CodeQL Call Graph Analysis](https://codeql.github.com/docs/writing-codeql-queries/about-data-flow-analysis/) diff --git a/server/ql/cpp/tools/src/PrintAST/PrintAST.md b/server/ql/cpp/tools/src/PrintAST/PrintAST.md new file mode 100644 index 0000000..1009845 --- /dev/null +++ b/server/ql/cpp/tools/src/PrintAST/PrintAST.md @@ -0,0 +1,58 @@ +# Print AST for C++ + +Outputs a representation of the Abstract Syntax Tree (AST) for specified source files. + +## Overview + +The Abstract Syntax Tree is a hierarchical representation of source code structure. Each node represents a syntactic construct (declaration, statement, expression, etc.) and edges represent parent-child containment relationships. + +This query produces the full AST for specified C++ source files, which is useful for understanding code structure, inspecting how the CodeQL extractor parses declarations and expressions, and debugging query logic that operates on AST nodes. + +## Use Cases + +This query is primarily used for: + +- Inspecting how CodeQL represents C++ declarations and expressions +- Debugging queries that match on AST node types +- Understanding parent-child relationships between classes, functions, and statements +- Verifying extractor behavior for templates, macros, and overloaded operators +- IDE integration for syntax tree visualization + +## Example + +The following C++ code demonstrates AST structure through declarations and statements: + +```cpp +#include + +class Example { +public: + void greet(const std::string& name) { // Function declaration in AST + std::cout << "Hello, " << name << "!" << std::endl; + } +}; + +int main() { // Top-level declaration + Example e; + e.greet("World"); + return 0; +} +``` + +In the resulting AST: + +- The class declaration contains member function declarations as children +- Each function body contains a statement list +- Call expressions reference their target and arguments as child nodes + +## Output Format + +The query produces a graph via the `PrintAstConfiguration` library: + +- `nodes`: Each AST node with its type, label, and properties +- `edges`: Parent-child relationships forming the syntax tree + +## References + +- [C++ Language Reference](https://en.cppreference.com/w/cpp/language) +- [CodeQL Abstract Syntax Trees](https://codeql.github.com/docs/writing-codeql-queries/abstract-syntax-tree/) diff --git a/server/ql/cpp/tools/src/PrintCFG/PrintCFG.md b/server/ql/cpp/tools/src/PrintCFG/PrintCFG.md index 534ac2a..f8c0e14 100644 --- a/server/ql/cpp/tools/src/PrintCFG/PrintCFG.md +++ b/server/ql/cpp/tools/src/PrintCFG/PrintCFG.md @@ -25,13 +25,13 @@ The following C++ code demonstrates control flow through conditional statements ```cpp void example(int x) { int result = 0; - if (x > 0) { // COMPLIANT - Branching creates CFG edges + if (x > 0) { // Branching creates CFG edges result = 1; } else { result = -1; } - for (int i = 0; i < 3; i++) { // COMPLIANT - Loop creates cyclic CFG + for (int i = 0; i < 3; i++) { // Loop creates cyclic CFG result = result + i; } } diff --git a/server/ql/cpp/tools/src/codeql-pack.yml b/server/ql/cpp/tools/src/codeql-pack.yml index c79e6b4..1c81dcf 100644 --- a/server/ql/cpp/tools/src/codeql-pack.yml +++ b/server/ql/cpp/tools/src/codeql-pack.yml @@ -1,5 +1,5 @@ name: advanced-security/ql-mcp-cpp-tools-src -version: 2.24.2 +version: 2.24.2-rc3 description: 'Queries for codeql-development-mcp-server tools for cpp language' library: false dependencies: diff --git a/server/ql/cpp/tools/test/codeql-pack.yml b/server/ql/cpp/tools/test/codeql-pack.yml index c78d47f..94bec74 100644 --- a/server/ql/cpp/tools/test/codeql-pack.yml +++ b/server/ql/cpp/tools/test/codeql-pack.yml @@ -1,5 +1,5 @@ name: advanced-security/ql-mcp-cpp-tools-test -version: 2.24.2 +version: 2.24.2-rc3 dependencies: advanced-security/ql-mcp-cpp-tools-src: ${workspace} extractor: cpp diff --git a/server/ql/csharp/tools/src/CallGraphFrom/CallGraphFrom.md b/server/ql/csharp/tools/src/CallGraphFrom/CallGraphFrom.md new file mode 100644 index 0000000..5c732b9 --- /dev/null +++ b/server/ql/csharp/tools/src/CallGraphFrom/CallGraphFrom.md @@ -0,0 +1,44 @@ +# CallGraphFrom for `csharp` Source Files + +Displays calls made from a specified method, showing the call graph outbound from the source method. + +## Overview + +This query identifies all method calls made within the body of a named method, producing an outbound call graph. Given a source method name, it reports each call site and the callee, which is useful for understanding method dependencies and call chains. + +The query accepts method names via an external predicate (`sourceFunction`). + +## Use Cases + +This query is primarily used for: + +- Mapping outbound dependencies of a specific method +- Understanding what a method calls and in what order +- Analyzing call chains for refactoring or security review + +## Example + +The following C# code demonstrates outbound calls from `SourceMethod`: + +```csharp +void Helper1() {} +void Helper2() { Helper1(); } + +void SourceMethod() { // Source method for analysis + Helper1(); + Helper2(); +} +``` + +Running with `sourceFunction = "SourceMethod"` produces results showing each call site with the message pattern ``Call from `SourceMethod` to `Helper1``. + +## Output Format + +The query is a `@kind problem` query producing rows of: + +- ``select call, "Call from `source` to `callee`"`` + +## References + +- [C# Methods](https://learn.microsoft.com/en-us/dotnet/csharp/methods) +- [CodeQL Call Graph Analysis](https://codeql.github.com/docs/writing-codeql-queries/about-data-flow-analysis/) diff --git a/server/ql/csharp/tools/src/CallGraphTo/CallGraphTo.md b/server/ql/csharp/tools/src/CallGraphTo/CallGraphTo.md new file mode 100644 index 0000000..f0f7bd7 --- /dev/null +++ b/server/ql/csharp/tools/src/CallGraphTo/CallGraphTo.md @@ -0,0 +1,41 @@ +# CallGraphTo for `csharp` Source Files + +Displays calls made to a specified method, showing the call graph inbound to the target method. + +## Overview + +This query identifies all call sites that invoke a named method, producing an inbound call graph. Given a target method name, it reports each caller and call location, which is useful for understanding how a method is used across the codebase. + +The query accepts method names via an external predicate (`targetFunction`). + +## Use Cases + +This query is primarily used for: + +- Finding all callers of a specific method +- Impact analysis before modifying a method signature +- Understanding usage patterns and entry points + +## Example + +The following C# code demonstrates inbound calls to `TargetMethod`: + +```csharp +void TargetMethod() {} // Target method for analysis + +void Caller1() { TargetMethod(); } +void Caller2() { TargetMethod(); } +``` + +Running with `targetFunction = "TargetMethod"` produces results showing each call site with the message pattern ``Call to `TargetMethod` from `Caller1``. + +## Output Format + +The query is a `@kind problem` query producing rows of: + +- ``select call, "Call to `target` from `caller`"`` + +## References + +- [C# Methods](https://learn.microsoft.com/en-us/dotnet/csharp/methods) +- [CodeQL Call Graph Analysis](https://codeql.github.com/docs/writing-codeql-queries/about-data-flow-analysis/) diff --git a/server/ql/csharp/tools/src/PrintAST/PrintAST.md b/server/ql/csharp/tools/src/PrintAST/PrintAST.md new file mode 100644 index 0000000..9f175b0 --- /dev/null +++ b/server/ql/csharp/tools/src/PrintAST/PrintAST.md @@ -0,0 +1,56 @@ +# Print AST for `csharp` Source Files + +Outputs a representation of the Abstract Syntax Tree (AST) for specified source files. + +## Overview + +The Abstract Syntax Tree is a hierarchical representation of source code structure. Each node represents a syntactic construct (declaration, statement, expression, etc.) and edges represent parent-child containment relationships. + +This query produces the full AST for specified C# source files, which is useful for understanding code structure, inspecting how the CodeQL extractor parses classes and methods, and debugging query logic that operates on AST nodes. + +## Use Cases + +This query is primarily used for: + +- Inspecting how CodeQL represents C# classes, methods, and expressions +- Debugging queries that match on AST node types +- Understanding parent-child relationships between namespaces, types, and members +- Verifying extractor behavior for generics, LINQ, and async/await patterns +- IDE integration for syntax tree visualization + +## Example + +The following C# code demonstrates AST structure through class and method declarations: + +```csharp +using System; + +public class Example { + public void Greet(string name) { // Method declaration in AST + Console.WriteLine($"Hello, {name}!"); + } + + public static void Main(string[] args) { // Entry point declaration + var e = new Example(); + e.Greet("World"); + } +} +``` + +In the resulting AST: + +- The class declaration contains method declarations as children +- Each method body contains a block with statement nodes +- Call expressions reference their target and arguments as child nodes + +## Output Format + +The query produces a graph via the `PrintAstConfiguration` library: + +- `nodes`: Each AST node with its type, label, and properties +- `edges`: Parent-child relationships forming the syntax tree + +## References + +- [C# Language Reference](https://learn.microsoft.com/en-us/dotnet/csharp/) +- [CodeQL Abstract Syntax Trees](https://codeql.github.com/docs/writing-codeql-queries/abstract-syntax-tree/) diff --git a/server/ql/csharp/tools/src/PrintCFG/PrintCFG.md b/server/ql/csharp/tools/src/PrintCFG/PrintCFG.md index f6a17e8..31451ef 100644 --- a/server/ql/csharp/tools/src/PrintCFG/PrintCFG.md +++ b/server/ql/csharp/tools/src/PrintCFG/PrintCFG.md @@ -24,13 +24,13 @@ The following C# code demonstrates control flow through conditional statements a ```csharp public void Example(int x) { - if (x > 0) { // COMPLIANT - Branching creates CFG edges + if (x > 0) { // Branching creates CFG edges Console.WriteLine("Positive"); } else { Console.WriteLine("Non-positive"); } - for (int i = 0; i < 3; i++) { // COMPLIANT - Loop creates cyclic CFG + for (int i = 0; i < 3; i++) { // Loop creates cyclic CFG Console.WriteLine(i); } } diff --git a/server/ql/csharp/tools/src/codeql-pack.yml b/server/ql/csharp/tools/src/codeql-pack.yml index 15050ce..c58c940 100644 --- a/server/ql/csharp/tools/src/codeql-pack.yml +++ b/server/ql/csharp/tools/src/codeql-pack.yml @@ -1,5 +1,5 @@ name: advanced-security/ql-mcp-csharp-tools-src -version: 2.24.2 +version: 2.24.2-rc3 description: 'Queries for codeql-development-mcp-server tools for csharp language' library: false dependencies: diff --git a/server/ql/csharp/tools/test/codeql-pack.yml b/server/ql/csharp/tools/test/codeql-pack.yml index bb0053c..f1d332c 100644 --- a/server/ql/csharp/tools/test/codeql-pack.yml +++ b/server/ql/csharp/tools/test/codeql-pack.yml @@ -1,5 +1,5 @@ name: advanced-security/ql-mcp-csharp-tools-test -version: 2.24.2 +version: 2.24.2-rc3 dependencies: advanced-security/ql-mcp-csharp-tools-src: ${workspace} extractor: csharp diff --git a/server/ql/go/tools/src/CallGraphFrom/CallGraphFrom.md b/server/ql/go/tools/src/CallGraphFrom/CallGraphFrom.md new file mode 100644 index 0000000..12e22f4 --- /dev/null +++ b/server/ql/go/tools/src/CallGraphFrom/CallGraphFrom.md @@ -0,0 +1,44 @@ +# CallGraphFrom for Go + +Displays calls made from a specified function, showing the call graph outbound from the source function. + +## Overview + +This query identifies all function calls made within the body of a named function, producing an outbound call graph. Given a source function name, it reports each call site and the callee, which is useful for understanding function dependencies and call chains. + +The query accepts function names via an external predicate (`sourceFunction`). + +## Use Cases + +This query is primarily used for: + +- Mapping outbound dependencies of a specific function +- Understanding what a function calls and in what order +- Analyzing call chains for refactoring or security review + +## Example + +The following Go code demonstrates outbound calls from `sourceFunc`: + +```go +func helper1() {} +func helper2() { helper1() } + +func sourceFunc() { // Source function for analysis + helper1() + helper2() +} +``` + +Running with `sourceFunction = "sourceFunc"` produces results showing each call site with the message pattern ``Call from `sourceFunc` to `helper1``. + +## Output Format + +The query is a `@kind problem` query producing rows of: + +- ``select call, "Call from `source` to `callee`"`` + +## References + +- [Go Functions](https://go.dev/doc/effective_go#functions) +- [CodeQL Call Graph Analysis](https://codeql.github.com/docs/writing-codeql-queries/about-data-flow-analysis/) diff --git a/server/ql/go/tools/src/CallGraphTo/CallGraphTo.md b/server/ql/go/tools/src/CallGraphTo/CallGraphTo.md new file mode 100644 index 0000000..b274a8c --- /dev/null +++ b/server/ql/go/tools/src/CallGraphTo/CallGraphTo.md @@ -0,0 +1,41 @@ +# CallGraphTo for Go + +Displays calls made to a specified function, showing the call graph inbound to the target function. + +## Overview + +This query identifies all call sites that invoke a named function, producing an inbound call graph. Given a target function name, it reports each caller and call location, which is useful for understanding how a function is used across the codebase. + +The query accepts function names via an external predicate (`targetFunction`). + +## Use Cases + +This query is primarily used for: + +- Finding all callers of a specific function +- Impact analysis before modifying a function signature +- Understanding usage patterns and entry points + +## Example + +The following Go code demonstrates inbound calls to `targetFunc`: + +```go +func targetFunc() {} // Target function for analysis + +func caller1() { targetFunc() } +func caller2() { targetFunc() } +``` + +Running with `targetFunction = "targetFunc"` produces results showing each call site with the message pattern ``Call to `targetFunc` from `caller1``. + +## Output Format + +The query is a `@kind problem` query producing rows of: + +- ``select call, "Call to `target` from `caller`"`` + +## References + +- [Go Functions](https://go.dev/doc/effective_go#functions) +- [CodeQL Call Graph Analysis](https://codeql.github.com/docs/writing-codeql-queries/about-data-flow-analysis/) diff --git a/server/ql/go/tools/src/PrintAST/PrintAST.md b/server/ql/go/tools/src/PrintAST/PrintAST.md new file mode 100644 index 0000000..7a7ebea --- /dev/null +++ b/server/ql/go/tools/src/PrintAST/PrintAST.md @@ -0,0 +1,55 @@ +# Print AST for Go + +Outputs a representation of the Abstract Syntax Tree (AST) for specified source files. + +## Overview + +The Abstract Syntax Tree is a hierarchical representation of source code structure. Each node represents a syntactic construct (declaration, statement, expression, etc.) and edges represent parent-child containment relationships. + +This query produces the full AST for specified Go source files, which is useful for understanding code structure, inspecting how the CodeQL extractor parses packages and functions, and debugging query logic that operates on AST nodes. + +## Use Cases + +This query is primarily used for: + +- Inspecting how CodeQL represents Go packages, functions, and expressions +- Debugging queries that match on AST node types +- Understanding parent-child relationships between declarations and statements +- Verifying extractor behavior for goroutines, channels, and interfaces +- IDE integration for syntax tree visualization + +## Example + +The following Go code demonstrates AST structure through function declarations and control flow: + +```go +package main + +import "fmt" + +func greet(name string) { // Function declaration in AST + fmt.Println("Hello, " + name + "!") +} + +func main() { // Entry point declaration + greet("World") +} +``` + +In the resulting AST: + +- The package declaration contains function declarations as children +- Each function body contains a block with statement nodes +- Call expressions reference their target and arguments as child nodes + +## Output Format + +The query produces a graph via the `PrintAstConfiguration` library: + +- `nodes`: Each AST node with its type, label, and properties +- `edges`: Parent-child relationships forming the syntax tree + +## References + +- [Go Language Specification](https://go.dev/ref/spec) +- [CodeQL Abstract Syntax Trees](https://codeql.github.com/docs/writing-codeql-queries/abstract-syntax-tree/) diff --git a/server/ql/go/tools/src/PrintCFG/PrintCFG.md b/server/ql/go/tools/src/PrintCFG/PrintCFG.md index c3f53d9..78a576e 100644 --- a/server/ql/go/tools/src/PrintCFG/PrintCFG.md +++ b/server/ql/go/tools/src/PrintCFG/PrintCFG.md @@ -24,13 +24,13 @@ The following Go code demonstrates control flow through conditional statements a ```go func example(x int) { - if x > 0 { // COMPLIANT - Branching creates CFG edges + if x > 0 { // Branching creates CFG edges fmt.Println("Positive") } else { fmt.Println("Non-positive") } - for i := 0; i < 3; i++ { // COMPLIANT - Loop creates cyclic CFG + for i := 0; i < 3; i++ { // Loop creates cyclic CFG fmt.Println(i) } } diff --git a/server/ql/go/tools/src/codeql-pack.yml b/server/ql/go/tools/src/codeql-pack.yml index f7e1f1c..ff5fa09 100644 --- a/server/ql/go/tools/src/codeql-pack.yml +++ b/server/ql/go/tools/src/codeql-pack.yml @@ -1,5 +1,5 @@ name: advanced-security/ql-mcp-go-tools-src -version: 2.24.2 +version: 2.24.2-rc3 description: 'Queries for codeql-development-mcp-server tools for go language' library: false dependencies: diff --git a/server/ql/go/tools/test/codeql-pack.yml b/server/ql/go/tools/test/codeql-pack.yml index 8baabe6..8b79c32 100644 --- a/server/ql/go/tools/test/codeql-pack.yml +++ b/server/ql/go/tools/test/codeql-pack.yml @@ -1,5 +1,5 @@ name: advanced-security/ql-mcp-go-tools-test -version: 2.24.2 +version: 2.24.2-rc3 dependencies: advanced-security/ql-mcp-go-tools-src: ${workspace} extractor: go diff --git a/server/ql/java/tools/src/CallGraphFrom/CallGraphFrom.md b/server/ql/java/tools/src/CallGraphFrom/CallGraphFrom.md new file mode 100644 index 0000000..5ba90c9 --- /dev/null +++ b/server/ql/java/tools/src/CallGraphFrom/CallGraphFrom.md @@ -0,0 +1,44 @@ +# CallGraphFrom for Java + +Displays calls made from a specified method, showing the call graph outbound from the source method. + +## Overview + +This query identifies all method calls made within the body of a named method, producing an outbound call graph. Given a source method name, it reports each call site and the callee, which is useful for understanding method dependencies and call chains. + +The query accepts method names via an external predicate (`sourceFunction`). + +## Use Cases + +This query is primarily used for: + +- Mapping outbound dependencies of a specific method +- Understanding what a method calls and in what order +- Analyzing call chains for refactoring or security review + +## Example + +The following Java code demonstrates outbound calls from `sourceMethod`: + +```java +void helper1() {} +void helper2() { helper1(); } + +void sourceMethod() { // Source method for analysis + helper1(); + helper2(); +} +``` + +Running with `sourceFunction = "sourceMethod"` produces results showing each call site with the message pattern ``Call from `sourceMethod` to `helper1``. + +## Output Format + +The query is a `@kind problem` query producing rows of: + +- ``select call, "Call from `source` to `callee`"`` + +## References + +- [Java Methods](https://docs.oracle.com/javase/tutorial/java/javaOO/methods.html) +- [CodeQL Call Graph Analysis](https://codeql.github.com/docs/writing-codeql-queries/about-data-flow-analysis/) diff --git a/server/ql/java/tools/src/CallGraphTo/CallGraphTo.md b/server/ql/java/tools/src/CallGraphTo/CallGraphTo.md new file mode 100644 index 0000000..eec85af --- /dev/null +++ b/server/ql/java/tools/src/CallGraphTo/CallGraphTo.md @@ -0,0 +1,41 @@ +# CallGraphTo for Java + +Displays calls made to a specified method, showing the call graph inbound to the target method. + +## Overview + +This query identifies all call sites that invoke a named method, producing an inbound call graph. Given a target method name, it reports each caller and call location, which is useful for understanding how a method is used across the codebase. + +The query accepts method names via an external predicate (`targetFunction`). + +## Use Cases + +This query is primarily used for: + +- Finding all callers of a specific method +- Impact analysis before modifying a method signature +- Understanding usage patterns and entry points + +## Example + +The following Java code demonstrates inbound calls to `targetMethod`: + +```java +void targetMethod() {} // Target method for analysis + +void caller1() { targetMethod(); } +void caller2() { targetMethod(); } +``` + +Running with `targetFunction = "targetMethod"` produces results showing each call site with the message pattern ``Call to `targetMethod` from `caller1``. + +## Output Format + +The query is a `@kind problem` query producing rows of: + +- ``select call, "Call to `target` from `caller`"`` + +## References + +- [Java Methods](https://docs.oracle.com/javase/tutorial/java/javaOO/methods.html) +- [CodeQL Call Graph Analysis](https://codeql.github.com/docs/writing-codeql-queries/about-data-flow-analysis/) diff --git a/server/ql/java/tools/src/PrintAST/PrintAST.md b/server/ql/java/tools/src/PrintAST/PrintAST.md new file mode 100644 index 0000000..baaf326 --- /dev/null +++ b/server/ql/java/tools/src/PrintAST/PrintAST.md @@ -0,0 +1,54 @@ +# Print AST for Java + +Outputs a representation of the Abstract Syntax Tree (AST) for specified source files. + +## Overview + +The Abstract Syntax Tree is a hierarchical representation of source code structure. Each node represents a syntactic construct (declaration, statement, expression, etc.) and edges represent parent-child containment relationships. + +This query produces the full AST for specified Java source files, which is useful for understanding code structure, inspecting how the CodeQL extractor parses classes and methods, and debugging query logic that operates on AST nodes. + +## Use Cases + +This query is primarily used for: + +- Inspecting how CodeQL represents Java classes, methods, and expressions +- Debugging queries that match on AST node types +- Understanding parent-child relationships between packages, types, and members +- Verifying extractor behavior for generics, annotations, and lambda expressions +- IDE integration for syntax tree visualization + +## Example + +The following Java code demonstrates AST structure through class and method declarations: + +```java +public class Example { + public void greet(String name) { // Method declaration in AST + System.out.println("Hello, " + name + "!"); + } + + public static void main(String[] args) { // Entry point declaration + Example e = new Example(); + e.greet("World"); + } +} +``` + +In the resulting AST: + +- The class declaration contains method declarations as children +- Each method body contains a block with statement nodes +- Call expressions reference their target and arguments as child nodes + +## Output Format + +The query produces a graph via the `PrintAstConfiguration` library: + +- `nodes`: Each AST node with its type, label, and properties +- `edges`: Parent-child relationships forming the syntax tree + +## References + +- [Java Language Specification](https://docs.oracle.com/javase/specs/) +- [CodeQL Abstract Syntax Trees](https://codeql.github.com/docs/writing-codeql-queries/abstract-syntax-tree/) diff --git a/server/ql/java/tools/src/PrintCFG/PrintCFG.md b/server/ql/java/tools/src/PrintCFG/PrintCFG.md index 5ef828f..bb727f2 100644 --- a/server/ql/java/tools/src/PrintCFG/PrintCFG.md +++ b/server/ql/java/tools/src/PrintCFG/PrintCFG.md @@ -24,13 +24,13 @@ The following Java code demonstrates control flow through conditional statements ```java public void example(int x) { - if (x > 0) { // COMPLIANT - Branching creates CFG edges + if (x > 0) { // Branching creates CFG edges System.out.println("Positive"); } else { System.out.println("Non-positive"); } - for (int i = 0; i < 3; i++) { // COMPLIANT - Loop creates cyclic CFG + for (int i = 0; i < 3; i++) { // Loop creates cyclic CFG System.out.println(i); } } diff --git a/server/ql/java/tools/src/codeql-pack.yml b/server/ql/java/tools/src/codeql-pack.yml index 506fb12..a80e6d2 100644 --- a/server/ql/java/tools/src/codeql-pack.yml +++ b/server/ql/java/tools/src/codeql-pack.yml @@ -1,5 +1,5 @@ name: advanced-security/ql-mcp-java-tools-src -version: 2.24.2 +version: 2.24.2-rc3 description: 'Queries for codeql-development-mcp-server tools for java language' library: false dependencies: diff --git a/server/ql/java/tools/test/codeql-pack.yml b/server/ql/java/tools/test/codeql-pack.yml index 6609173..989c59c 100644 --- a/server/ql/java/tools/test/codeql-pack.yml +++ b/server/ql/java/tools/test/codeql-pack.yml @@ -1,5 +1,5 @@ name: advanced-security/ql-mcp-java-tools-test -version: 2.24.2 +version: 2.24.2-rc3 dependencies: advanced-security/ql-mcp-java-tools-src: ${workspace} extractor: java diff --git a/server/ql/javascript/tools/src/CallGraphFrom/CallGraphFrom.md b/server/ql/javascript/tools/src/CallGraphFrom/CallGraphFrom.md new file mode 100644 index 0000000..bc57c40 --- /dev/null +++ b/server/ql/javascript/tools/src/CallGraphFrom/CallGraphFrom.md @@ -0,0 +1,47 @@ +# CallGraphFrom for JavaScript + +Displays calls made from a specified function, showing the call graph outbound from the source function. + +## Overview + +This query identifies all function calls made within the body of a named function, producing an outbound call graph. Given a source function name, it reports each call site and the callee, which is useful for understanding function dependencies and call chains. + +The query accepts function names via an external predicate (`sourceFunction`). + +## Use Cases + +This query is primarily used for: + +- Mapping outbound dependencies of a specific function +- Understanding what a function calls and in what order +- Analyzing call chains for refactoring or security review + +## Example + +The following JavaScript code demonstrates outbound calls from `sourceFunc`: + +```javascript +function helper1() {} +function helper2() { + helper1(); +} + +function sourceFunc() { + // Source function for analysis + helper1(); + helper2(); +} +``` + +Running with `sourceFunction = "sourceFunc"` produces results showing each call site with the message pattern ``Call from `sourceFunc` to `helper1``. + +## Output Format + +The query is a `@kind problem` query producing rows of: + +- ``select call, "Call from `source` to `callee`"`` + +## References + +- [JavaScript Functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions) +- [CodeQL Call Graph Analysis](https://codeql.github.com/docs/writing-codeql-queries/about-data-flow-analysis/) diff --git a/server/ql/javascript/tools/src/CallGraphTo/CallGraphTo.md b/server/ql/javascript/tools/src/CallGraphTo/CallGraphTo.md new file mode 100644 index 0000000..8deacbd --- /dev/null +++ b/server/ql/javascript/tools/src/CallGraphTo/CallGraphTo.md @@ -0,0 +1,45 @@ +# CallGraphTo for JavaScript + +Displays calls made to a specified function, showing the call graph inbound to the target function. + +## Overview + +This query identifies all call sites that invoke a named function, producing an inbound call graph. Given a target function name, it reports each caller and call location, which is useful for understanding how a function is used across the codebase. + +The query accepts function names via an external predicate (`targetFunction`). + +## Use Cases + +This query is primarily used for: + +- Finding all callers of a specific function +- Impact analysis before modifying a function signature +- Understanding usage patterns and entry points + +## Example + +The following JavaScript code demonstrates inbound calls to `targetFunc`: + +```javascript +function targetFunc() {} // Target function for analysis + +function caller1() { + targetFunc(); +} +function caller2() { + targetFunc(); +} +``` + +Running with `targetFunction = "targetFunc"` produces results showing each call site with the message pattern ``Call to `targetFunc` from `caller1``. + +## Output Format + +The query is a `@kind problem` query producing rows of: + +- ``select call, "Call to `target` from `caller`"`` + +## References + +- [JavaScript Functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions) +- [CodeQL Call Graph Analysis](https://codeql.github.com/docs/writing-codeql-queries/about-data-flow-analysis/) diff --git a/server/ql/javascript/tools/src/PrintAST/PrintAST.md b/server/ql/javascript/tools/src/PrintAST/PrintAST.md new file mode 100644 index 0000000..5a06f08 --- /dev/null +++ b/server/ql/javascript/tools/src/PrintAST/PrintAST.md @@ -0,0 +1,58 @@ +# Print AST for JavaScript + +Outputs a representation of the Abstract Syntax Tree (AST) for specified source files. + +## Overview + +The Abstract Syntax Tree is a hierarchical representation of source code structure. Each node represents a syntactic construct (declaration, statement, expression, etc.) and edges represent parent-child containment relationships. + +This query produces the full AST for specified JavaScript source files, which is useful for understanding code structure, inspecting how the CodeQL extractor parses functions and expressions, and debugging query logic that operates on AST nodes. + +## Use Cases + +This query is primarily used for: + +- Inspecting how CodeQL represents JavaScript functions, classes, and expressions +- Debugging queries that match on AST node types +- Understanding parent-child relationships between modules, declarations, and statements +- Verifying extractor behavior for arrow functions, destructuring, and async/await +- IDE integration for syntax tree visualization + +## Example + +The following JavaScript code demonstrates AST structure through function and class declarations: + +```javascript +class Example { + constructor(name = 'World') { + // Constructor in AST + this.name = name; + } + + greet() { + // Method declaration in AST + console.log(`Hello, ${this.name}!`); + } +} + +const e = new Example(); +e.greet(); +``` + +In the resulting AST: + +- The class declaration contains method definitions as children +- Each method body contains a block with statement nodes +- Call expressions and template literals reference their components as child nodes + +## Output Format + +The query produces a graph via the `PrintAstConfiguration` library: + +- `nodes`: Each AST node with its type, label, and properties +- `edges`: Parent-child relationships forming the syntax tree + +## References + +- [JavaScript Language Reference](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference) +- [CodeQL Abstract Syntax Trees](https://codeql.github.com/docs/writing-codeql-queries/abstract-syntax-tree/) diff --git a/server/ql/javascript/tools/src/PrintCFG/PrintCFG.md b/server/ql/javascript/tools/src/PrintCFG/PrintCFG.md index c080035..5982de3 100644 --- a/server/ql/javascript/tools/src/PrintCFG/PrintCFG.md +++ b/server/ql/javascript/tools/src/PrintCFG/PrintCFG.md @@ -25,14 +25,14 @@ The following JavaScript code demonstrates control flow through conditional stat ```javascript function example(x) { if (x > 0) { - // COMPLIANT - Branching creates CFG edges + // Branching creates CFG edges console.log('Positive'); } else { console.log('Non-positive'); } for (let i = 0; i < 3; i++) { - // COMPLIANT - Loop creates cyclic CFG + // Loop creates cyclic CFG console.log(i); } } diff --git a/server/ql/javascript/tools/src/codeql-pack.yml b/server/ql/javascript/tools/src/codeql-pack.yml index 225b734..7ceffb0 100644 --- a/server/ql/javascript/tools/src/codeql-pack.yml +++ b/server/ql/javascript/tools/src/codeql-pack.yml @@ -1,5 +1,5 @@ name: advanced-security/ql-mcp-javascript-tools-src -version: 2.24.2 +version: 2.24.2-rc3 description: 'Queries for codeql-development-mcp-server tools for javascript language' library: false dependencies: diff --git a/server/ql/javascript/tools/test/codeql-pack.yml b/server/ql/javascript/tools/test/codeql-pack.yml index 3c9532b..c61410c 100644 --- a/server/ql/javascript/tools/test/codeql-pack.yml +++ b/server/ql/javascript/tools/test/codeql-pack.yml @@ -1,5 +1,5 @@ name: advanced-security/ql-mcp-javascript-tools-test -version: 2.24.2 +version: 2.24.2-rc3 dependencies: advanced-security/ql-mcp-javascript-tools-src: ${workspace} extractor: javascript diff --git a/server/ql/python/tools/src/CallGraphFrom/CallGraphFrom.md b/server/ql/python/tools/src/CallGraphFrom/CallGraphFrom.md new file mode 100644 index 0000000..8adc0a0 --- /dev/null +++ b/server/ql/python/tools/src/CallGraphFrom/CallGraphFrom.md @@ -0,0 +1,46 @@ +# CallGraphFrom for Python + +Displays calls made from a specified function, showing the call graph outbound from the source function. + +## Overview + +This query identifies all function calls made within the body of a named function, producing an outbound call graph. Given a source function name, it reports each call site and the callee, which is useful for understanding function dependencies and call chains. + +The query accepts function names via an external predicate (`sourceFunction`). + +## Use Cases + +This query is primarily used for: + +- Mapping outbound dependencies of a specific function +- Understanding what a function calls and in what order +- Analyzing call chains for refactoring or security review + +## Example + +The following Python code demonstrates outbound calls from `source_func`: + +```python +def helper1(): + pass + +def helper2(): + helper1() + +def source_func(): # Source function for analysis + helper1() + helper2() +``` + +Running with `sourceFunction = "source_func"` produces results showing each call site with the message pattern ``Call from `source_func` to `helper1``. + +## Output Format + +The query is a `@kind problem` query producing rows of: + +- ``select call, "Call from `source` to `callee`"`` + +## References + +- [Python Functions](https://docs.python.org/3/tutorial/controlflow.html#defining-functions) +- [CodeQL Call Graph Analysis](https://codeql.github.com/docs/writing-codeql-queries/about-data-flow-analysis/) diff --git a/server/ql/python/tools/src/CallGraphTo/CallGraphTo.md b/server/ql/python/tools/src/CallGraphTo/CallGraphTo.md new file mode 100644 index 0000000..573a75b --- /dev/null +++ b/server/ql/python/tools/src/CallGraphTo/CallGraphTo.md @@ -0,0 +1,45 @@ +# CallGraphTo for Python + +Displays calls made to a specified function, showing the call graph inbound to the target function. + +## Overview + +This query identifies all call sites that invoke a named function, producing an inbound call graph. Given a target function name, it reports each caller and call location, which is useful for understanding how a function is used across the codebase. + +The query accepts function names via an external predicate (`targetFunction`). + +## Use Cases + +This query is primarily used for: + +- Finding all callers of a specific function +- Impact analysis before modifying a function signature +- Understanding usage patterns and entry points + +## Example + +The following Python code demonstrates inbound calls to `target_func`: + +```python +def target_func(): # Target function for analysis + pass + +def caller1(): + target_func() + +def caller2(): + target_func() +``` + +Running with `targetFunction = "target_func"` produces results showing each call site with the message pattern ``Call to `target_func` from `caller1``. + +## Output Format + +The query is a `@kind problem` query producing rows of: + +- ``select call, "Call to `target` from `caller`"`` + +## References + +- [Python Functions](https://docs.python.org/3/tutorial/controlflow.html#defining-functions) +- [CodeQL Call Graph Analysis](https://codeql.github.com/docs/writing-codeql-queries/about-data-flow-analysis/) diff --git a/server/ql/python/tools/src/PrintAST/PrintAST.md b/server/ql/python/tools/src/PrintAST/PrintAST.md new file mode 100644 index 0000000..0f8eec5 --- /dev/null +++ b/server/ql/python/tools/src/PrintAST/PrintAST.md @@ -0,0 +1,53 @@ +# Print AST for Python + +Outputs a representation of the Abstract Syntax Tree (AST) for specified source files. + +## Overview + +The Abstract Syntax Tree is a hierarchical representation of source code structure. Each node represents a syntactic construct (declaration, statement, expression, etc.) and edges represent parent-child containment relationships. + +This query produces the full AST for specified Python source files, which is useful for understanding code structure, inspecting how the CodeQL extractor parses classes and functions, and debugging query logic that operates on AST nodes. + +## Use Cases + +This query is primarily used for: + +- Inspecting how CodeQL represents Python classes, functions, and expressions +- Debugging queries that match on AST node types +- Understanding parent-child relationships between modules, classes, and statements +- Verifying extractor behavior for decorators, comprehensions, and f-strings +- IDE integration for syntax tree visualization + +## Example + +The following Python code demonstrates AST structure through class and function declarations: + +```python +class Example: + def __init__(self, name="World"): # Method definition in AST + self.name = name + + def greet(self): # Method definition in AST + print(f"Hello, {self.name}!") + +example = Example() +example.greet() +``` + +In the resulting AST: + +- The class definition contains function definitions as children +- Each function body contains a statement list +- Call expressions and f-strings reference their components as child nodes + +## Output Format + +The query produces a graph via the `PrintAstConfiguration` library: + +- `nodes`: Each AST node with its type, label, and properties +- `edges`: Parent-child relationships forming the syntax tree + +## References + +- [Python Language Reference](https://docs.python.org/3/reference/) +- [CodeQL Abstract Syntax Trees](https://codeql.github.com/docs/writing-codeql-queries/abstract-syntax-tree/) diff --git a/server/ql/python/tools/src/PrintCFG/PrintCFG.md b/server/ql/python/tools/src/PrintCFG/PrintCFG.md index 83df781..7b273b4 100644 --- a/server/ql/python/tools/src/PrintCFG/PrintCFG.md +++ b/server/ql/python/tools/src/PrintCFG/PrintCFG.md @@ -24,12 +24,12 @@ The following Python code demonstrates control flow through conditional statemen ```python def example(x): - if x > 0: # COMPLIANT - Branching creates CFG edges + if x > 0: # Branching creates CFG edges print("Positive") else: print("Non-positive") - for i in range(3): # COMPLIANT - Loop creates cyclic CFG + for i in range(3): # Loop creates cyclic CFG print(i) ``` diff --git a/server/ql/python/tools/src/codeql-pack.yml b/server/ql/python/tools/src/codeql-pack.yml index 5a8af5f..60f1220 100644 --- a/server/ql/python/tools/src/codeql-pack.yml +++ b/server/ql/python/tools/src/codeql-pack.yml @@ -1,5 +1,5 @@ name: advanced-security/ql-mcp-python-tools-src -version: 2.24.2 +version: 2.24.2-rc3 description: 'Queries for codeql-development-mcp-server tools for python language' library: false dependencies: diff --git a/server/ql/python/tools/test/codeql-pack.yml b/server/ql/python/tools/test/codeql-pack.yml index 2ece56a..09f8316 100644 --- a/server/ql/python/tools/test/codeql-pack.yml +++ b/server/ql/python/tools/test/codeql-pack.yml @@ -1,5 +1,5 @@ name: advanced-security/ql-mcp-python-tools-test -version: 2.24.2 +version: 2.24.2-rc3 dependencies: advanced-security/ql-mcp-python-tools-src: ${workspace} extractor: python diff --git a/server/ql/ruby/tools/src/CallGraphFrom/CallGraphFrom.md b/server/ql/ruby/tools/src/CallGraphFrom/CallGraphFrom.md new file mode 100644 index 0000000..58dcc41 --- /dev/null +++ b/server/ql/ruby/tools/src/CallGraphFrom/CallGraphFrom.md @@ -0,0 +1,48 @@ +# CallGraphFrom for Ruby + +Displays calls made from a specified method, showing the call graph outbound from the source method. + +## Overview + +This query identifies all method calls made within the body of a named method, producing an outbound call graph. Given a source method name, it reports each call site and the callee, which is useful for understanding method dependencies and call chains. + +The query accepts method names via an external predicate (`sourceFunction`). + +## Use Cases + +This query is primarily used for: + +- Mapping outbound dependencies of a specific method +- Understanding what a method calls and in what order +- Analyzing call chains for refactoring or security review + +## Example + +The following Ruby code demonstrates outbound calls from `source_func`: + +```ruby +def helper1 +end + +def helper2 + helper1 +end + +def source_func # Source method for analysis + helper1 + helper2 +end +``` + +Running with `sourceFunction = "source_func"` produces results showing each call site with the message pattern ``Call from `source_func` to `helper1``. + +## Output Format + +The query is a `@kind problem` query producing rows of: + +- ``select call, "Call from `source` to `callee`"`` + +## References + +- [Ruby Methods](https://ruby-doc.org/core/doc/syntax/methods_rdoc.html) +- [CodeQL Call Graph Analysis](https://codeql.github.com/docs/writing-codeql-queries/about-data-flow-analysis/) diff --git a/server/ql/ruby/tools/src/CallGraphTo/CallGraphTo.md b/server/ql/ruby/tools/src/CallGraphTo/CallGraphTo.md new file mode 100644 index 0000000..1086328 --- /dev/null +++ b/server/ql/ruby/tools/src/CallGraphTo/CallGraphTo.md @@ -0,0 +1,47 @@ +# CallGraphTo for Ruby + +Displays calls made to a specified method, showing the call graph inbound to the target method. + +## Overview + +This query identifies all call sites that invoke a named method, producing an inbound call graph. Given a target method name, it reports each caller and call location, which is useful for understanding how a method is used across the codebase. + +The query accepts method names via an external predicate (`targetFunction`). + +## Use Cases + +This query is primarily used for: + +- Finding all callers of a specific method +- Impact analysis before modifying a method signature +- Understanding usage patterns and entry points + +## Example + +The following Ruby code demonstrates inbound calls to `target_func`: + +```ruby +def target_func # Target method for analysis +end + +def caller1 + target_func +end + +def caller2 + target_func +end +``` + +Running with `targetFunction = "target_func"` produces results showing each call site with the message pattern ``Call to `target_func` from `caller1``. + +## Output Format + +The query is a `@kind problem` query producing rows of: + +- ``select call, "Call to `target` from `caller`"`` + +## References + +- [Ruby Methods](https://ruby-doc.org/core/doc/syntax/methods_rdoc.html) +- [CodeQL Call Graph Analysis](https://codeql.github.com/docs/writing-codeql-queries/about-data-flow-analysis/) diff --git a/server/ql/ruby/tools/src/PrintAST/PrintAST.md b/server/ql/ruby/tools/src/PrintAST/PrintAST.md new file mode 100644 index 0000000..7ea5483 --- /dev/null +++ b/server/ql/ruby/tools/src/PrintAST/PrintAST.md @@ -0,0 +1,56 @@ +# Print AST for Ruby + +Outputs a representation of the Abstract Syntax Tree (AST) for specified source files. + +## Overview + +The Abstract Syntax Tree is a hierarchical representation of source code structure. Each node represents a syntactic construct (declaration, statement, expression, etc.) and edges represent parent-child containment relationships. + +This query produces the full AST for specified Ruby source files, which is useful for understanding code structure, inspecting how the CodeQL extractor parses classes and methods, and debugging query logic that operates on AST nodes. + +## Use Cases + +This query is primarily used for: + +- Inspecting how CodeQL represents Ruby classes, methods, and expressions +- Debugging queries that match on AST node types +- Understanding parent-child relationships between modules, classes, and methods +- Verifying extractor behavior for blocks, procs, and metaprogramming constructs +- IDE integration for syntax tree visualization + +## Example + +The following Ruby code demonstrates AST structure through class and method definitions: + +```ruby +class Example + def initialize(name = "World") # Method definition in AST + @name = name + end + + def greet # Method definition in AST + puts "Hello, #{@name}!" + end +end + +e = Example.new +e.greet +``` + +In the resulting AST: + +- The class definition contains method definitions as children +- Each method body contains a statement list +- Method calls and string interpolations reference their components as child nodes + +## Output Format + +The query produces a graph via the `PrintAstConfiguration` library: + +- `nodes`: Each AST node with its type, label, and properties +- `edges`: Parent-child relationships forming the syntax tree + +## References + +- [Ruby Language Documentation](https://ruby-doc.org/core/) +- [CodeQL Abstract Syntax Trees](https://codeql.github.com/docs/writing-codeql-queries/abstract-syntax-tree/) diff --git a/server/ql/ruby/tools/src/PrintCFG/PrintCFG.md b/server/ql/ruby/tools/src/PrintCFG/PrintCFG.md index c5af857..110d049 100644 --- a/server/ql/ruby/tools/src/PrintCFG/PrintCFG.md +++ b/server/ql/ruby/tools/src/PrintCFG/PrintCFG.md @@ -24,13 +24,13 @@ The following Ruby code demonstrates control flow through conditional statements ```ruby def example(x) - if x > 0 # COMPLIANT - Branching creates CFG edges + if x > 0 # Branching creates CFG edges puts "Positive" else puts "Non-positive" end - (0..2).each do |i| # COMPLIANT - Iterator creates CFG paths + (0..2).each do |i| # Iterator creates CFG paths puts i end end diff --git a/server/ql/ruby/tools/src/codeql-pack.yml b/server/ql/ruby/tools/src/codeql-pack.yml index 3b18548..a519205 100644 --- a/server/ql/ruby/tools/src/codeql-pack.yml +++ b/server/ql/ruby/tools/src/codeql-pack.yml @@ -1,5 +1,5 @@ name: advanced-security/ql-mcp-ruby-tools-src -version: 2.24.2 +version: 2.24.2-rc3 description: 'Queries for codeql-development-mcp-server tools for ruby language' library: false dependencies: diff --git a/server/ql/ruby/tools/test/codeql-pack.yml b/server/ql/ruby/tools/test/codeql-pack.yml index 09d87cf..4952204 100644 --- a/server/ql/ruby/tools/test/codeql-pack.yml +++ b/server/ql/ruby/tools/test/codeql-pack.yml @@ -1,5 +1,5 @@ name: advanced-security/ql-mcp-ruby-tools-test -version: 2.24.2 +version: 2.24.2-rc3 dependencies: advanced-security/ql-mcp-ruby-tools-src: ${workspace} extractor: ruby diff --git a/server/ql/swift/tools/src/CallGraphFrom/CallGraphFrom.md b/server/ql/swift/tools/src/CallGraphFrom/CallGraphFrom.md new file mode 100644 index 0000000..646f182 --- /dev/null +++ b/server/ql/swift/tools/src/CallGraphFrom/CallGraphFrom.md @@ -0,0 +1,44 @@ +# CallGraphFrom for Swift + +Displays calls made from a specified function, showing the call graph outbound from the source function. + +## Overview + +This query identifies all function calls made within the body of a named function, producing an outbound call graph. Given a source function name, it reports each call site and the callee, which is useful for understanding function dependencies and call chains. + +The query accepts function names via an external predicate (`sourceFunction`). + +## Use Cases + +This query is primarily used for: + +- Mapping outbound dependencies of a specific function +- Understanding what a function calls and in what order +- Analyzing call chains for refactoring or security review + +## Example + +The following Swift code demonstrates outbound calls from `sourceFunc`: + +```swift +func helper1() {} +func helper2() { helper1() } + +func sourceFunc() { // Source function for analysis + helper1() + helper2() +} +``` + +Running with `sourceFunction = "sourceFunc"` produces results showing each call site with the message pattern ``Call from `sourceFunc` to `helper1``. + +## Output Format + +The query is a `@kind problem` query producing rows of: + +- ``select call, "Call from `source` to `callee`"`` + +## References + +- [Swift Functions](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/functions/) +- [CodeQL Call Graph Analysis](https://codeql.github.com/docs/writing-codeql-queries/about-data-flow-analysis/) diff --git a/server/ql/swift/tools/src/CallGraphTo/CallGraphTo.md b/server/ql/swift/tools/src/CallGraphTo/CallGraphTo.md new file mode 100644 index 0000000..1356ad4 --- /dev/null +++ b/server/ql/swift/tools/src/CallGraphTo/CallGraphTo.md @@ -0,0 +1,41 @@ +# CallGraphTo for Swift + +Displays calls made to a specified function, showing the call graph inbound to the target function. + +## Overview + +This query identifies all call sites that invoke a named function, producing an inbound call graph. Given a target function name, it reports each caller and call location, which is useful for understanding how a function is used across the codebase. + +The query accepts function names via an external predicate (`targetFunction`). + +## Use Cases + +This query is primarily used for: + +- Finding all callers of a specific function +- Impact analysis before modifying a function signature +- Understanding usage patterns and entry points + +## Example + +The following Swift code demonstrates inbound calls to `targetFunc`: + +```swift +func targetFunc() {} // Target function for analysis + +func caller1() { targetFunc() } +func caller2() { targetFunc() } +``` + +Running with `targetFunction = "targetFunc"` produces results showing each call site with the message pattern ``Call to `targetFunc` from `caller1``. + +## Output Format + +The query is a `@kind problem` query producing rows of: + +- ``select call, "Call to `target` from `caller`"`` + +## References + +- [Swift Functions](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/functions/) +- [CodeQL Call Graph Analysis](https://codeql.github.com/docs/writing-codeql-queries/about-data-flow-analysis/) diff --git a/server/ql/swift/tools/src/PrintAST/PrintAST.md b/server/ql/swift/tools/src/PrintAST/PrintAST.md new file mode 100644 index 0000000..14e68b1 --- /dev/null +++ b/server/ql/swift/tools/src/PrintAST/PrintAST.md @@ -0,0 +1,54 @@ +# Print AST for Swift + +Outputs a representation of the Abstract Syntax Tree (AST) for specified source files. + +## Overview + +The Abstract Syntax Tree is a hierarchical representation of source code structure. Each node represents a syntactic construct (declaration, statement, expression, etc.) and edges represent parent-child containment relationships. + +This query produces the full AST for specified Swift source files, which is useful for understanding code structure, inspecting how the CodeQL extractor parses types and functions, and debugging query logic that operates on AST nodes. + +## Use Cases + +This query is primarily used for: + +- Inspecting how CodeQL represents Swift structs, classes, and functions +- Debugging queries that match on AST node types +- Understanding parent-child relationships between declarations and expressions +- Verifying extractor behavior for closures, optionals, and protocol conformances +- IDE integration for syntax tree visualization + +## Example + +The following Swift code demonstrates AST structure through struct and function declarations: + +```swift +struct Example { + let name: String + + func greet() { // Function declaration in AST + print("Hello, \(name)!") + } +} + +let e = Example(name: "World") // Initializer call in AST +e.greet() +``` + +In the resulting AST: + +- The struct declaration contains property and function declarations as children +- Each function body contains a brace statement with expression nodes +- Call expressions and string interpolations reference their components as child nodes + +## Output Format + +The query produces a graph via the `PrintAstConfiguration` library: + +- `nodes`: Each AST node with its type, label, and properties +- `edges`: Parent-child relationships forming the syntax tree + +## References + +- [Swift Language Guide](https://docs.swift.org/swift-book/) +- [CodeQL Abstract Syntax Trees](https://codeql.github.com/docs/writing-codeql-queries/abstract-syntax-tree/) diff --git a/server/ql/swift/tools/src/PrintCFG/PrintCFG.md b/server/ql/swift/tools/src/PrintCFG/PrintCFG.md new file mode 100644 index 0000000..9f267b5 --- /dev/null +++ b/server/ql/swift/tools/src/PrintCFG/PrintCFG.md @@ -0,0 +1,55 @@ +# Print CFG for Swift + +Produces a representation of a file's Control Flow Graph (CFG) for specified source files. + +## Overview + +The Control Flow Graph represents the order in which statements and expressions are executed in a program. Each node in the graph represents a control-flow element (statement or expression), and edges represent possible execution paths between them. + +This query outputs all CFG nodes and their successor relationships for Swift code, which is useful for understanding program execution flow, debugging control flow issues, and analyzing code paths. + +## Use Cases + +This query is primarily used for: + +- Visualizing program execution flow +- Understanding complex branching logic +- Debugging control flow issues +- Analysis of code paths and reachability +- IDE integration for control flow visualization + +## Example + +The following Swift code demonstrates control flow through conditional statements and loops: + +```swift +func example(x: Int) { + if x > 0 { // Branching creates CFG edges + print("Positive") + } else { + print("Non-positive") + } + + for i in 0..<3 { // Loop creates cyclic CFG + print(i) + } +} +``` + +In the resulting CFG: + +- The `if` condition creates two outgoing edges (true/false branches) +- The `for-in` loop creates a cycle back to the iterator +- Each statement connects to its successor in execution order + +## Output Format + +The query produces two relations: + +- `nodes(ControlFlowNode, string, string)`: Each CFG node with its label +- `edges(ControlFlowNode, ControlFlowNode)`: Successor relationships between nodes + +## References + +- [Swift Control Flow](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/controlflow/) +- [CodeQL Control Flow Graph](https://codeql.github.com/docs/writing-codeql-queries/about-control-flow-in-codeql/) diff --git a/server/ql/swift/tools/src/codeql-pack.yml b/server/ql/swift/tools/src/codeql-pack.yml index e136311..6979a96 100644 --- a/server/ql/swift/tools/src/codeql-pack.yml +++ b/server/ql/swift/tools/src/codeql-pack.yml @@ -1,5 +1,5 @@ name: advanced-security/ql-mcp-swift-tools-src -version: 2.24.2 +version: 2.24.2-rc3 description: 'Queries for codeql-development-mcp-server tools for swift language' library: false dependencies: diff --git a/server/ql/swift/tools/test/codeql-pack.yml b/server/ql/swift/tools/test/codeql-pack.yml index bc7f36d..be0928d 100644 --- a/server/ql/swift/tools/test/codeql-pack.yml +++ b/server/ql/swift/tools/test/codeql-pack.yml @@ -1,5 +1,5 @@ name: advanced-security/ql-mcp-swift-tools-test -version: 2.24.2 +version: 2.24.2-rc3 dependencies: advanced-security/ql-mcp-swift-tools-src: ${workspace} extractor: swift diff --git a/server/test/src/tools/query-documentation.test.ts b/server/test/src/tools/query-documentation.test.ts new file mode 100644 index 0000000..0f067cd --- /dev/null +++ b/server/test/src/tools/query-documentation.test.ts @@ -0,0 +1,78 @@ +/** + * Tests that every server/ql tools query (.ql) has a matching + * documentation file (.md) in the same directory. + * + * This is a filesystem-level guard that runs as part of the standard + * `npm test` suite and will fail the build if any documentation is + * missing. + */ + +import { describe, it, expect } from 'vitest'; +import * as fs from 'fs'; +import * as path from 'path'; +import { fileURLToPath } from 'url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +/** Absolute path to `server/ql` within the repository. */ +const QL_ROOT = path.resolve(__dirname, '..', '..', '..', 'ql'); + +/** + * Recursively discover all `.ql` files under `server/ql//tools/src/`. + */ +function discoverToolsQueries(): string[] { + const queries: string[] = []; + + // Each language directory under server/ql/ + const languages = fs + .readdirSync(QL_ROOT, { withFileTypes: true }) + .filter((d) => d.isDirectory()) + .map((d) => d.name); + + for (const lang of languages) { + const toolsSrcDir = path.join(QL_ROOT, lang, 'tools', 'src'); + if (!fs.existsSync(toolsSrcDir)) continue; + + // Each query directory under tools/src/ + const queryDirs = fs + .readdirSync(toolsSrcDir, { withFileTypes: true }) + .filter((d) => d.isDirectory()) + .map((d) => d.name); + + for (const queryDir of queryDirs) { + const qlFile = path.join(toolsSrcDir, queryDir, `${queryDir}.ql`); + if (fs.existsSync(qlFile)) { + queries.push(qlFile); + } + } + } + + return queries.sort(); +} + +describe('Tools query documentation', () => { + const queries = discoverToolsQueries(); + + it('should discover at least one tools query', () => { + expect(queries.length).toBeGreaterThan(0); + }); + + it('every tools query (.ql) should have a matching documentation file (.md)', () => { + const missing: string[] = []; + + for (const qlFile of queries) { + const mdFile = qlFile.replace(/\.ql$/, '.md'); + if (!fs.existsSync(mdFile)) { + // Report workspace-relative path for readability + const relative = path.relative(path.resolve(QL_ROOT, '..'), mdFile); + missing.push(relative); + } + } + + expect( + missing, + `Missing documentation files:\n ${missing.join('\n ')}` + ).toHaveLength(0); + }); +});