-
Notifications
You must be signed in to change notification settings - Fork 226
Resolve model editor queries from CodeQL packs if present #2872
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| import { Mode } from "./shared/mode"; | ||
| import { assertNever } from "../common/helpers-pure"; | ||
|
|
||
| export function modeTag(mode: Mode): string { | ||
| switch (mode) { | ||
| case Mode.Application: | ||
| return "application-mode"; | ||
| case Mode.Framework: | ||
| return "framework-mode"; | ||
| default: | ||
| assertNever(mode); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,9 +5,27 @@ import { dump } from "js-yaml"; | |
| import { prepareExternalApiQuery } from "./external-api-usage-queries"; | ||
| import { CodeQLCliServer } from "../codeql-cli/cli"; | ||
| import { showLlmGeneration } from "../config"; | ||
| import { Mode } from "./shared/mode"; | ||
| import { resolveQueriesFromPacks } from "../local-queries"; | ||
| import { modeTag } from "./mode-tag"; | ||
|
|
||
| export const syntheticQueryPackName = "codeql/external-api-usage"; | ||
|
|
||
| /** | ||
| * setUpPack sets up a directory to use for the data extension editor queries. | ||
| * setUpPack sets up a directory to use for the data extension editor queries if required. | ||
| * | ||
| * There are two cases (example language is Java): | ||
| * - In case the queries are present in the codeql/java-queries, we don't need to write our own queries | ||
| * to disk. We still need to create a synthetic query pack so we can pass the queryDir to the query | ||
| * resolver without caring about whether the queries are present in the pack or not. | ||
| * - In case the queries are not present in the codeql/java-queries, we need to write our own queries | ||
| * to disk. We will create a synthetic query pack and install its dependencies so it is fully independent | ||
| * and we can simply pass it through when resolving the queries. | ||
| * | ||
| * These steps together ensure that later steps of the process don't need to keep track of whether the queries | ||
| * are present in codeql/java-queries or in our own query pack. They just need to resolve the query. | ||
| * | ||
| * @param cliServer The CodeQL CLI server to use. | ||
| * @param queryDir The directory to set up. | ||
| * @param language The language to use for the queries. | ||
| * @returns true if the setup was successful, false otherwise. | ||
|
|
@@ -17,34 +35,104 @@ export async function setUpPack( | |
| queryDir: string, | ||
| language: QueryLanguage, | ||
| ): Promise<boolean> { | ||
| // Create the external API query | ||
| const externalApiQuerySuccess = await prepareExternalApiQuery( | ||
| queryDir, | ||
| // Download the required query packs | ||
| await cliServer.packDownload([`codeql/${language}-queries`]); | ||
|
|
||
| // We'll only check if the application mode query exists in the pack and assume that if it does, | ||
| // the framework mode query will also exist. | ||
| const applicationModeQuery = await resolveEndpointsQuery( | ||
| cliServer, | ||
| language, | ||
| Mode.Application, | ||
| [], | ||
| [], | ||
| ); | ||
| if (!externalApiQuerySuccess) { | ||
| return false; | ||
| } | ||
|
|
||
| // Set up a synthetic pack so that the query can be resolved later. | ||
| const syntheticQueryPack = { | ||
| name: "codeql/external-api-usage", | ||
| version: "0.0.0", | ||
| dependencies: { | ||
| [`codeql/${language}-all`]: "*", | ||
| }, | ||
| }; | ||
| if (applicationModeQuery) { | ||
| // Set up a synthetic pack so CodeQL doesn't crash later when we try | ||
| // to resolve a query within this directory | ||
| const syntheticQueryPack = { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is basically unused right? it just needs to exist to satisfy the
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, exactly. This is just to reduce the amount of state that would need to be passed around between |
||
| name: syntheticQueryPackName, | ||
| version: "0.0.0", | ||
| dependencies: {}, | ||
| }; | ||
|
|
||
| const qlpackFile = join(queryDir, "codeql-pack.yml"); | ||
| await writeFile(qlpackFile, dump(syntheticQueryPack), "utf8"); | ||
| await cliServer.packInstall(queryDir); | ||
| const qlpackFile = join(queryDir, "codeql-pack.yml"); | ||
| await writeFile(qlpackFile, dump(syntheticQueryPack), "utf8"); | ||
| } else { | ||
| // If we can't resolve the query, we need to write them to desk ourselves. | ||
| const externalApiQuerySuccess = await prepareExternalApiQuery( | ||
| queryDir, | ||
| language, | ||
| ); | ||
| if (!externalApiQuerySuccess) { | ||
| return false; | ||
| } | ||
|
|
||
| // Install the other needed query packs | ||
| await cliServer.packDownload([`codeql/${language}-queries`]); | ||
| // Set up a synthetic pack so that the query can be resolved later. | ||
| const syntheticQueryPack = { | ||
| name: syntheticQueryPackName, | ||
| version: "0.0.0", | ||
| dependencies: { | ||
| [`codeql/${language}-all`]: "*", | ||
| }, | ||
| }; | ||
|
|
||
| const qlpackFile = join(queryDir, "codeql-pack.yml"); | ||
| await writeFile(qlpackFile, dump(syntheticQueryPack), "utf8"); | ||
| await cliServer.packInstall(queryDir); | ||
| } | ||
|
|
||
| // Download any other required packs | ||
| if (language === "java" && showLlmGeneration()) { | ||
| await cliServer.packDownload([`codeql/${language}-automodel-queries`]); | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| /** | ||
| * Resolve the query path to the model editor endpoints query. All queries are tagged like this: | ||
| * modeleditor endpoints <mode> | ||
| * Example: modeleditor endpoints framework-mode | ||
| * | ||
| * @param cliServer The CodeQL CLI server to use. | ||
| * @param language The language of the query pack to use. | ||
| * @param mode The mode to resolve the query for. | ||
| * @param additionalPackNames Additional pack names to search. | ||
| * @param additionalPackPaths Additional pack paths to search. | ||
| */ | ||
| export async function resolveEndpointsQuery( | ||
| cliServer: CodeQLCliServer, | ||
| language: string, | ||
| mode: Mode, | ||
| additionalPackNames: string[] = [], | ||
| additionalPackPaths: string[] = [], | ||
| ): Promise<string | undefined> { | ||
| const packsToSearch = [`codeql/${language}-queries`, ...additionalPackNames]; | ||
|
|
||
| // First, resolve the query that we want to run. | ||
| // All queries are tagged like this: | ||
| // internal extract automodel <mode> <queryTag> | ||
| // Example: internal extract automodel framework-mode candidates | ||
| const queries = await resolveQueriesFromPacks( | ||
| cliServer, | ||
| packsToSearch, | ||
| { | ||
| kind: "table", | ||
| "tags contain all": ["modeleditor", "endpoints", modeTag(mode)], | ||
| }, | ||
| additionalPackPaths, | ||
| ); | ||
| if (queries.length > 1) { | ||
| throw new Error( | ||
| `Found multiple endpoints queries for ${mode}. Can't continue`, | ||
| ); | ||
| } | ||
|
|
||
| if (queries.length === 0) { | ||
| return undefined; | ||
| } | ||
|
|
||
| return queries[0]; | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.