@@ -5,9 +5,28 @@ import { dump } from "js-yaml";
55import { prepareExternalApiQuery } from "./external-api-usage-queries" ;
66import { CodeQLCliServer } from "../codeql-cli/cli" ;
77import { showLlmGeneration } from "../config" ;
8+ import { Mode } from "./shared/mode" ;
9+ import { resolveQueries } from "../local-queries" ;
10+ import { modeTag } from "./mode-tag" ;
11+ import { extLogger } from "../common/logging/vscode" ;
12+
13+ export const syntheticQueryPackName = "codeql/external-api-usage" ;
814
915/**
10- * setUpPack sets up a directory to use for the data extension editor queries.
16+ * setUpPack sets up a directory to use for the data extension editor queries if required.
17+ *
18+ * There are two cases (example language is Java):
19+ * - In case the queries are present in the codeql/java-queries, we don't need to write our own queries
20+ * to disk. We still need to create a synthetic query pack so we can pass the queryDir to the query
21+ * resolver without caring about whether the queries are present in the pack or not.
22+ * - In case the queries are not present in the codeql/java-queries, we need to write our own queries
23+ * to disk. We will create a synthetic query pack and install its dependencies so it is fully independent
24+ * and we can simply pass it through when resolving the queries.
25+ *
26+ * These steps together ensure that later steps of the process don't need to keep track of whether the queries
27+ * are present in codeql/java-queries or in our own query pack. They just need to resolve the query.
28+ *
29+ * @param cliServer The CodeQL CLI server to use.
1130 * @param queryDir The directory to set up.
1231 * @param language The language to use for the queries.
1332 * @returns true if the setup was successful, false otherwise.
@@ -17,34 +36,111 @@ export async function setUpPack(
1736 queryDir : string ,
1837 language : QueryLanguage ,
1938) : Promise < boolean > {
20- // Create the external API query
21- const externalApiQuerySuccess = await prepareExternalApiQuery (
22- queryDir ,
39+ // Download the required query packs
40+ await cliServer . packDownload ( [ `codeql/${ language } -queries` ] ) ;
41+
42+ const applicationModeQuery = await resolveEndpointsQuery (
43+ cliServer ,
2344 language ,
45+ Mode . Application ,
46+ [ ] ,
47+ [ ] ,
48+ true ,
2449 ) ;
25- if ( ! externalApiQuerySuccess ) {
26- return false ;
27- }
2850
29- // Set up a synthetic pack so that the query can be resolved later.
30- const syntheticQueryPack = {
31- name : "codeql/external-api-usage" ,
32- version : "0.0.0" ,
33- dependencies : {
34- [ `codeql/${ language } -all` ] : "*" ,
35- } ,
36- } ;
51+ if ( applicationModeQuery ) {
52+ void extLogger . log ( "Using application mode queries" ) ;
3753
38- const qlpackFile = join ( queryDir , "codeql-pack.yml" ) ;
39- await writeFile ( qlpackFile , dump ( syntheticQueryPack ) , "utf8" ) ;
40- await cliServer . packInstall ( queryDir ) ;
54+ // Set up a synthetic pack so CodeQL doesn't crash later when we try
55+ // to resolve a query within this directory
56+ const syntheticQueryPack = {
57+ name : syntheticQueryPackName ,
58+ version : "0.0.0" ,
59+ dependencies : { } ,
60+ } ;
4161
42- // Install the other needed query packs
43- await cliServer . packDownload ( [ `codeql/${ language } -queries` ] ) ;
62+ const qlpackFile = join ( queryDir , "codeql-pack.yml" ) ;
63+ await writeFile ( qlpackFile , dump ( syntheticQueryPack ) , "utf8" ) ;
64+ } else {
65+ void extLogger . log ( "Writing external API usage queries to disk" ) ;
4466
67+ // If we can't resolve the query, we need to write them to desk ourselves.
68+ const externalApiQuerySuccess = await prepareExternalApiQuery (
69+ queryDir ,
70+ language ,
71+ ) ;
72+ if ( ! externalApiQuerySuccess ) {
73+ return false ;
74+ }
75+
76+ // Set up a synthetic pack so that the query can be resolved later.
77+ const syntheticQueryPack = {
78+ name : syntheticQueryPackName ,
79+ version : "0.0.0" ,
80+ dependencies : {
81+ [ `codeql/${ language } -all` ] : "*" ,
82+ } ,
83+ } ;
84+
85+ const qlpackFile = join ( queryDir , "codeql-pack.yml" ) ;
86+ await writeFile ( qlpackFile , dump ( syntheticQueryPack ) , "utf8" ) ;
87+ await cliServer . packInstall ( queryDir ) ;
88+ }
89+
90+ // Download any other required packs
4591 if ( language === "java" && showLlmGeneration ( ) ) {
4692 await cliServer . packDownload ( [ `codeql/${ language } -automodel-queries` ] ) ;
4793 }
4894
4995 return true ;
5096}
97+
98+ /**
99+ * Resolve the query path to the model editor endpoints query. All queries are tagged like this:
100+ * modeleditor endpoints <mode>
101+ * Example: modeleditor endpoints framework-mode
102+ *
103+ * @param cliServer The CodeQL CLI server to use.
104+ * @param language The language of the query pack to use.
105+ * @param mode The mode to resolve the query for.
106+ * @param additionalPackNames Additional pack names to search.
107+ * @param additionalPackPaths Additional pack paths to search.
108+ * @param allowNoQueriesFound If true, will not throw an error if no queries are found.
109+ */
110+ export async function resolveEndpointsQuery (
111+ cliServer : CodeQLCliServer ,
112+ language : string ,
113+ mode : Mode ,
114+ additionalPackNames : string [ ] = [ ] ,
115+ additionalPackPaths : string [ ] = [ ] ,
116+ allowNoQueriesFound = false ,
117+ ) : Promise < string | undefined > {
118+ const packsToSearch = [ `codeql/${ language } -queries` , ...additionalPackNames ] ;
119+
120+ // First, resolve the query that we want to run.
121+ // All queries are tagged like this:
122+ // internal extract automodel <mode> <queryTag>
123+ // Example: internal extract automodel framework-mode candidates
124+ const queries = await resolveQueries (
125+ cliServer ,
126+ packsToSearch ,
127+ `Fetch endpoints query for ${ mode } ` ,
128+ {
129+ kind : "table" ,
130+ "tags contain all" : [ "modeleditor" , "endpoints" , modeTag ( mode ) ] ,
131+ } ,
132+ allowNoQueriesFound ,
133+ additionalPackPaths ,
134+ ) ;
135+ if ( queries . length > 1 ) {
136+ throw new Error (
137+ `Found multiple endpoints queries for ${ mode } . Can't continue` ,
138+ ) ;
139+ }
140+
141+ if ( queries . length === 0 ) {
142+ return undefined ;
143+ }
144+
145+ return queries [ 0 ] ;
146+ }
0 commit comments