@@ -2,6 +2,7 @@ package main
22
33import (
44 "bufio"
5+ "bytes"
56 "flag"
67 "fmt"
78 "log"
@@ -103,7 +104,7 @@ func buildGroupExternalArgs(queries []config.Query, extroot string) []string {
103104//
104105// Results are placed at <dbPath>/results/<queryPack>/<queryPathNoExt>.bqrs.
105106// Decoded output goes to <dbPath>/results/<queryPack>/<queryPathNoExt>.<tgtFmt>.
106- func runQueriesOnDB (cfg * config.Artifact , db config.DB , queryRoot string , queries []config.Query , tgtFmt string ) {
107+ func runQueriesOnDB (cfg * config.Artifact , db config.DB , packName , queryRoot string , queries []config.Query , tgtFmt string ) {
107108 // --- Phase 1: run-queries ---
108109 extArgs := buildGroupExternalArgs (queries , db .ExtDir ())
109110
@@ -140,8 +141,8 @@ func runQueriesOnDB(cfg *config.Artifact, db config.DB, queryRoot string, querie
140141 utils .MkdirAll (decodeLogDir )
141142
142143 for _ , query := range queries {
143- bqrsPath := filepath .Join (db .Path (), "results/lslightly/qlstat" , query .PathNoExt ()+ ".bqrs" )
144- csvPath := filepath .Join (db .Path (), "results/lslightly/qlstat" , query .PathNoExt ()+ "." + tgtFmt )
144+ bqrsPath := filepath .Join (db .Path (), "results" , packName , query .PathNoExt ()+ ".bqrs" )
145+ csvPath := filepath .Join (db .Path (), "results" , packName , query .PathNoExt ()+ "." + tgtFmt )
145146
146147 decOut , decErr := utils .CreateOutAndErr (filepath .Join (decodeLogDir , query .Name ()))
147148 cmd := exec .Command ("codeql" , "bqrs" , "decode" ,
@@ -166,6 +167,7 @@ dump stdout/stderr for ${db} in ${config.OutResultRoot}/${qScriptNameNoExt}/log/
166167*/
167168func queriesExec (cfg * config.Artifact , grp config.QueryGroup , queryRoot string , tgtFmt string ) {
168169 dbs := cfg .ConvStrSliceToDBSlice (grp .QueryDBs )
170+ packName := resolvePackName (grp )
169171
170172 // Create Query objects for all queries in the group
171173 queries := make ([]config.Query , len (grp .Queries ))
@@ -180,7 +182,7 @@ func queriesExec(cfg *config.Artifact, grp config.QueryGroup, queryRoot string,
180182 wg .Add (1 )
181183 go func (db config.DB ) {
182184 defer wg .Done ()
183- runQueriesOnDB (cfg , db , queryRoot , queries , tgtFmt )
185+ runQueriesOnDB (cfg , db , packName , queryRoot , queries , tgtFmt )
184186 bar .Describe (fmt .Sprintf ("db: %-20s %d queries" , db .Name , len (queries )))
185187 bar .Add (1 )
186188 }(db )
@@ -201,7 +203,7 @@ func checkDecodeTargetFmt(tgtFmt string) bool {
201203}
202204
203205/*
204- codeql bqrs decode --format=${tgtFmt} ${dbPath}/results/lslightly/qlstat/ ${queryPathNoExt}.bqrs --output=${dbPath}/results/lslightly/qlstat /${queryPathNoExt}.${tgtFmt}
206+ codeql bqrs decode --format=${tgtFmt} ${dbPath}/results/${queryPack}/ ${queryPathNoExt}.bqrs --output=${dbPath}/results/${queryPack} /${queryPathNoExt}.${tgtFmt}
205207*/
206208func decodeResults (cfg * config.Artifact , tgtFmt string ) {
207209 checkDecodeTargetFmt (tgtFmt )
@@ -210,12 +212,14 @@ func decodeResults(cfg *config.Artifact, tgtFmt string) {
210212 dbs := cfg .ConvStrSliceToDBSlice (grp .QueryDBs )
211213 queries := grp .Queries
212214
215+ packName := resolvePackName (grp )
216+
213217 bar := progressbar .Default (int64 (len (queries ) * len (dbs )))
214218 for _ , qScript := range queries {
215219 query := config .CreateQuery (qScript , grp .Externals , grp .ExternalFiles , grp .ResolvedExternalRoot ())
216220 for _ , db := range dbs {
217- bqrsPath := filepath .Join (db .Path (), "results/lslightly/qlstat" , query .PathNoExt ()+ ".bqrs" )
218- csvPath := filepath .Join (db .Path (), "results/lslightly/qlstat" , query .PathNoExt ()+ "." + tgtFmt )
221+ bqrsPath := filepath .Join (db .Path (), "results" , packName , query .PathNoExt ()+ ".bqrs" )
222+ csvPath := filepath .Join (db .Path (), "results" , packName , query .PathNoExt ()+ "." + tgtFmt )
219223
220224 decodeLogDir := filepath .Join (cfg .PassLogDir ("decode" ), db .Name )
221225 utils .MkdirAll (decodeLogDir )
@@ -242,19 +246,50 @@ func decodeResults(cfg *config.Artifact, tgtFmt string) {
242246
243247// -- CSV collection ------------------------------------------------------
244248
249+ // resolvePackName resolves the CodeQL pack name for a query group.
250+ // "std" or empty QueryRoot → built-in pack "lslightly/qlstat".
251+ // Otherwise runs "codeql resolve queries" on the first query to get the pack name.
252+ // Only one .ql file per group is needed — same QueryRoot → same qlpack.
253+ func resolvePackName (grp config.QueryGroup ) string {
254+ if grp .QueryRoot == "" || grp .QueryRoot == "std" {
255+ return "lslightly/qlstat"
256+ }
257+ if len (grp .Queries ) == 0 {
258+ return "lslightly/qlstat"
259+ }
260+ qPath := filepath .Join (grp .ResolvedQueryRoot (), grp .Queries [0 ])
261+ var errBuf bytes.Buffer
262+ cmd := exec .Command ("codeql" , "resolve" , "queries" , qPath )
263+ cmd .Stderr = & errBuf
264+ err := cmd .Run ()
265+ if err != nil {
266+ log .Fatalf ("Failed to resolve pack for query %s: %v\n Output: %s" , qPath , err , errBuf .String ())
267+ }
268+ // Parse: "Recording pack reference <pack-name> at <path>"
269+ line := strings .TrimSpace (errBuf .String ())
270+ prefix := "Recording pack reference "
271+ rest := strings .TrimPrefix (line , prefix )
272+ before , _ , found := strings .Cut (rest , " at " )
273+ if ! found {
274+ log .Fatalf ("Unexpected codeql resolve output format for %s: %s" , qPath , rest )
275+ }
276+ return before
277+ }
278+
245279func collectCSVs (cfg * config.Artifact ) {
246280 for grpi , grp := range cfg .QueryGrps {
281+ packName := resolvePackName (grp )
247282 bar := progressbar .Default (int64 (len (grp .Queries )))
248283 for _ , qScript := range grp .Queries {
249284 query := config .CreateQuery (qScript , grp .Externals , grp .ExternalFiles , grp .ResolvedExternalRoot ())
250285 bar .Describe (fmt .Sprintf ("Grp %d: Collecting for " + query .PathNoExt (), grpi ))
251- collectCSVsForQuery (cfg , query , grp )
286+ collectCSVsForQuery (cfg , query , grp , packName )
252287 bar .Add (1 )
253288 }
254289 }
255290}
256291
257- func collectCSVsForQuery (cfg * config.Artifact , query config.Query , grp config.QueryGroup ) {
292+ func collectCSVsForQuery (cfg * config.Artifact , query config.Query , grp config.QueryGroup , packName string ) {
258293 qResultCSV := query .DirPath (cfg .ResultRoot ) + ".csv"
259294
260295 outFile := utils .CreateFile (qResultCSV )
@@ -269,7 +304,7 @@ func collectCSVsForQuery(cfg *config.Artifact, query config.Query, grp config.Qu
269304
270305 var wg sync.WaitGroup
271306 for _ , db := range dbs {
272- csvPath := filepath .Join (db .Path (), "results/lslightly/qlstat" , query .PathNoExt ()+ ".csv" )
307+ csvPath := filepath .Join (db .Path (), "results" , packName , query .PathNoExt ()+ ".csv" )
273308
274309 // Check if the csv file exists
275310 if _ , err := os .Stat (csvPath ); os .IsNotExist (err ) {
0 commit comments