diff --git a/extensions/ql-vscode/CHANGELOG.md b/extensions/ql-vscode/CHANGELOG.md index d60414bcab6..d7767ac0d14 100644 --- a/extensions/ql-vscode/CHANGELOG.md +++ b/extensions/ql-vscode/CHANGELOG.md @@ -2,6 +2,8 @@ ## [UNRELEASED] +- Stop allowing running MRVA with a query outside of the workspace. [#3302](https://github.com/github/vscode-codeql/pull/3302) + ## 1.12.1 - 31 January 2024 - Enable collection of telemetry for the `codeQL.addingDatabases.addDatabaseSourceToWorkspace` setting. [#3238](https://github.com/github/vscode-codeql/pull/3238) diff --git a/extensions/ql-vscode/src/common/files.ts b/extensions/ql-vscode/src/common/files.ts index 64016e99583..c5b9b66a9bd 100644 --- a/extensions/ql-vscode/src/common/files.ts +++ b/extensions/ql-vscode/src/common/files.ts @@ -1,4 +1,4 @@ -import { pathExists, stat, readdir, opendir } from "fs-extra"; +import { pathExists, stat, readdir, opendir, lstatSync } from "fs-extra"; import { dirname, isAbsolute, join, relative, resolve } from "path"; import { tmpdir as osTmpdir } from "os"; @@ -149,6 +149,11 @@ export function findCommonParentDir(...paths: string[]): string { paths = paths.map((path) => normalizePath(path)); + // If there's only one path and it's a file, return its dirname + if (paths.length === 1) { + return lstatSync(paths[0]).isFile() ? dirname(paths[0]) : paths[0]; + } + let commonDir = paths[0]; while (!paths.every((path) => containsPath(commonDir, path))) { if (isTopLevelPath(commonDir)) { diff --git a/extensions/ql-vscode/src/variant-analysis/ql.ts b/extensions/ql-vscode/src/variant-analysis/ql.ts index bd8dc6be64f..10be3258bb7 100644 --- a/extensions/ql-vscode/src/variant-analysis/ql.ts +++ b/extensions/ql-vscode/src/variant-analysis/ql.ts @@ -1,4 +1,3 @@ -import { dirname } from "path"; import { containsPath, findCommonParentDir } from "../common/files"; import { findPackRoot } from "../common/ql"; @@ -9,8 +8,8 @@ import { findPackRoot } from "../common/ql"; * - If all query files are in the same QL pack, it returns the root directory of that pack. * - If the query files are in different QL packs, it throws an error. * - If some query files are in a QL pack and some aren't, it throws an error. - * - If none of the query files are in a QL pack, it returns the common parent directory of the query files. However, - * if there are more than one query files and they're not in the same workspace folder, it throws an error. + * - If none of the query files are in a QL pack, it returns the common parent directory of the query + * files. However, if the common parent directory is not in a workspace folder, it throws an error. * * @param queryFiles - An array of file paths for the query files. * @param workspaceFolders - An array of workspace folder paths. @@ -31,10 +30,6 @@ export async function findVariantAnalysisQlPackRoot( packRoots.push(packRoot); } - if (queryFiles.length === 1) { - return packRoots[0] ?? dirname(queryFiles[0]); - } - const uniquePackRoots = Array.from(new Set(packRoots)); if (uniquePackRoots.length > 1) { diff --git a/extensions/ql-vscode/test/unit-tests/common/files.test.ts b/extensions/ql-vscode/test/unit-tests/common/files.test.ts index ad04b81b0b0..789b5d52f0f 100644 --- a/extensions/ql-vscode/test/unit-tests/common/files.test.ts +++ b/extensions/ql-vscode/test/unit-tests/common/files.test.ts @@ -541,14 +541,6 @@ describe("findCommonParentDir", () => { expect(commonDir).toEqualPath(rootDir); }); - it("should handle a single path", async () => { - const paths = [join("/foo", "bar", "baz")]; - - const commonDir = findCommonParentDir(...paths); - - expect(commonDir).toEqualPath(join("/foo", "bar", "baz")); - }); - it("should return the same path if all paths are identical", () => { const paths = [ join("/foo", "bar", "baz"), @@ -580,4 +572,23 @@ describe("findCommonParentDir", () => { expect(commonDir).toEqualPath(rootDir); }); + + it("should return the parent dir of a single file", async () => { + const dataDir = join(__dirname, "../../data"); + const paths = [dataDir]; + + const commonDir = findCommonParentDir(...paths); + + expect(commonDir).toEqualPath(dataDir); + }); + + it("should return the dir if a single dir is provided", async () => { + const dataDir = join(__dirname, "../../data"); + const filePath = join(dataDir, "query.ql"); + const paths = [filePath]; + + const commonDir = findCommonParentDir(...paths); + + expect(commonDir).toEqualPath(dataDir); + }); }); diff --git a/extensions/ql-vscode/test/unit-tests/variant-analysis/ql.test.ts b/extensions/ql-vscode/test/unit-tests/variant-analysis/ql.test.ts index 6a77d0108a1..d9f6a0d6589 100644 --- a/extensions/ql-vscode/test/unit-tests/variant-analysis/ql.test.ts +++ b/extensions/ql-vscode/test/unit-tests/variant-analysis/ql.test.ts @@ -45,15 +45,15 @@ describe("findVariantAnalysisQlPackRoot", () => { expect(packRoot).toEqualPath(getFullPath("workspace1")); }); - it("should return the pack root of a single query not in a pack or workspace", async () => { - const queryFiles = [getFullPath("dir1/query1.ql")]; + it("should fail if single query not in a pack or workspace", async () => { + const queryFiles = [getFullPath("workspace1/query1.ql")]; + const workspaceFolders = [getFullPath("workspace2")]; - const packRoot = await findVariantAnalysisQlPackRoot( - queryFiles, - workspaceFolders, + await expect( + findVariantAnalysisQlPackRoot(queryFiles, workspaceFolders), + ).rejects.toThrow( + "All queries must be within the workspace and within the same workspace root", ); - - expect(packRoot).toEqualPath(getFullPath("dir1")); }); it("should throw an error if some queries are in a pack and some are not", async () => {