Add createInitWithConfigStatusReport function

This commit is contained in:
Michael B. Gale
2025-09-04 10:16:25 +01:00
parent da9299646d
commit 37ddb03e0d
4 changed files with 254 additions and 218 deletions

97
lib/init-action.js generated
View File

@@ -89988,6 +89988,51 @@ async function sendStatusReport(statusReport) {
);
}
}
async function createInitWithConfigStatusReport(config, initStatusReport, configFile, totalCacheSize, overlayBaseDatabaseStats) {
const languages = config.languages.join(",");
const paths = (config.originalUserInput.paths || []).join(",");
const pathsIgnore = (config.originalUserInput["paths-ignore"] || []).join(
","
);
const disableDefaultQueries = config.originalUserInput["disable-default-queries"] ? languages : "";
const queries = [];
let queriesInput = getOptionalInput("queries")?.trim();
if (queriesInput === void 0 || queriesInput.startsWith("+")) {
queries.push(
...(config.originalUserInput.queries || []).map((q) => q.uses)
);
}
if (queriesInput !== void 0) {
queriesInput = queriesInput.startsWith("+") ? queriesInput.slice(1) : queriesInput;
queries.push(...queriesInput.split(","));
}
let packs = {};
if (Array.isArray(config.computedConfig.packs)) {
packs[config.languages[0]] = config.computedConfig.packs;
} else if (config.computedConfig.packs !== void 0) {
packs = config.computedConfig.packs;
}
return {
...initStatusReport,
config_file: configFile ?? "",
disable_default_queries: disableDefaultQueries,
paths,
paths_ignore: pathsIgnore,
queries: queries.join(","),
packs: JSON.stringify(packs),
trap_cache_languages: Object.keys(config.trapCaches).join(","),
trap_cache_download_size_bytes: totalCacheSize,
trap_cache_download_duration_ms: Math.round(config.trapCacheDownloadTime),
overlay_base_database_download_size_bytes: overlayBaseDatabaseStats?.databaseSizeBytes,
overlay_base_database_download_duration_ms: overlayBaseDatabaseStats?.databaseDownloadDurationMs,
query_filters: JSON.stringify(
config.originalUserInput["query-filters"] ?? []
),
registries: JSON.stringify(
parseRegistriesWithoutCredentials(getOptionalInput("registries")) ?? []
)
};
}
// src/workflow.ts
var fs16 = __toESM(require("fs"));
@@ -90175,53 +90220,15 @@ async function sendCompletedStatusReport(startedAt, config, configFile, toolsDow
initToolsDownloadFields.tools_feature_flags_valid = toolsFeatureFlagsValid;
}
if (config !== void 0) {
const languages = config.languages.join(",");
const paths = (config.originalUserInput.paths || []).join(",");
const pathsIgnore = (config.originalUserInput["paths-ignore"] || []).join(
","
);
const disableDefaultQueries = config.originalUserInput["disable-default-queries"] ? languages : "";
const queries = [];
let queriesInput = getOptionalInput("queries")?.trim();
if (queriesInput === void 0 || queriesInput.startsWith("+")) {
queries.push(
...(config.originalUserInput.queries || []).map((q) => q.uses)
);
}
if (queriesInput !== void 0) {
queriesInput = queriesInput.startsWith("+") ? queriesInput.slice(1) : queriesInput;
queries.push(...queriesInput.split(","));
}
let packs = {};
if (Array.isArray(config.computedConfig.packs)) {
packs[config.languages[0]] = config.computedConfig.packs;
} else if (config.computedConfig.packs !== void 0) {
packs = config.computedConfig.packs;
}
const initWithConfigStatusReport = {
...initStatusReport,
config_file: configFile ?? "",
disable_default_queries: disableDefaultQueries,
paths,
paths_ignore: pathsIgnore,
queries: queries.join(","),
packs: JSON.stringify(packs),
trap_cache_languages: Object.keys(config.trapCaches).join(","),
trap_cache_download_size_bytes: Math.round(
const initWithConfigStatusReport = await createInitWithConfigStatusReport(
config,
initStatusReport,
configFile,
Math.round(
await getTotalCacheSize(Object.values(config.trapCaches), logger)
),
trap_cache_download_duration_ms: Math.round(config.trapCacheDownloadTime),
overlay_base_database_download_size_bytes: overlayBaseDatabaseStats?.databaseSizeBytes,
overlay_base_database_download_duration_ms: overlayBaseDatabaseStats?.databaseDownloadDurationMs,
query_filters: JSON.stringify(
config.originalUserInput["query-filters"] ?? []
),
registries: JSON.stringify(
parseRegistriesWithoutCredentials(
getOptionalInput("registries")
) ?? []
)
};
overlayBaseDatabaseStats
);
await sendStatusReport({
...initWithConfigStatusReport,
...initToolsDownloadFields

View File

@@ -89580,7 +89580,111 @@ var GitHubFeatureFlags = class {
// src/status-report.ts
var os = __toESM(require("os"));
var core9 = __toESM(require_core());
// src/config-utils.ts
var fs8 = __toESM(require("fs"));
var path10 = __toESM(require("path"));
var semver4 = __toESM(require_semver2());
// src/analyses.ts
var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => {
AnalysisKind2["CodeScanning"] = "code-scanning";
AnalysisKind2["CodeQuality"] = "code-quality";
return AnalysisKind2;
})(AnalysisKind || {});
var supportedAnalysisKinds = new Set(Object.values(AnalysisKind));
// src/caching-utils.ts
var core8 = __toESM(require_core());
// src/diff-informed-analysis-utils.ts
var fs7 = __toESM(require("fs"));
var path9 = __toESM(require("path"));
function getDiffRangesJsonFilePath() {
return path9.join(getTemporaryDirectory(), "pr-diff-range.json");
}
function readDiffRangesJsonFile(logger) {
const jsonFilePath = getDiffRangesJsonFilePath();
if (!fs7.existsSync(jsonFilePath)) {
logger.debug(`Diff ranges JSON file does not exist at ${jsonFilePath}`);
return void 0;
}
const jsonContents = fs7.readFileSync(jsonFilePath, "utf8");
logger.debug(
`Read pr-diff-range JSON file from ${jsonFilePath}:
${jsonContents}`
);
return JSON.parse(jsonContents);
}
// src/trap-caching.ts
var actionsCache2 = __toESM(require_cache3());
// src/config-utils.ts
var OVERLAY_ANALYSIS_FEATURES = {
actions: "overlay_analysis_actions" /* OverlayAnalysisActions */,
cpp: "overlay_analysis_cpp" /* OverlayAnalysisCpp */,
csharp: "overlay_analysis_csharp" /* OverlayAnalysisCsharp */,
go: "overlay_analysis_go" /* OverlayAnalysisGo */,
java: "overlay_analysis_java" /* OverlayAnalysisJava */,
javascript: "overlay_analysis_javascript" /* OverlayAnalysisJavascript */,
python: "overlay_analysis_python" /* OverlayAnalysisPython */,
ruby: "overlay_analysis_ruby" /* OverlayAnalysisRuby */,
rust: "overlay_analysis_rust" /* OverlayAnalysisRust */,
swift: "overlay_analysis_swift" /* OverlayAnalysisSwift */
};
var OVERLAY_ANALYSIS_CODE_SCANNING_FEATURES = {
actions: "overlay_analysis_code_scanning_actions" /* OverlayAnalysisCodeScanningActions */,
cpp: "overlay_analysis_code_scanning_cpp" /* OverlayAnalysisCodeScanningCpp */,
csharp: "overlay_analysis_code_scanning_csharp" /* OverlayAnalysisCodeScanningCsharp */,
go: "overlay_analysis_code_scanning_go" /* OverlayAnalysisCodeScanningGo */,
java: "overlay_analysis_code_scanning_java" /* OverlayAnalysisCodeScanningJava */,
javascript: "overlay_analysis_code_scanning_javascript" /* OverlayAnalysisCodeScanningJavascript */,
python: "overlay_analysis_code_scanning_python" /* OverlayAnalysisCodeScanningPython */,
ruby: "overlay_analysis_code_scanning_ruby" /* OverlayAnalysisCodeScanningRuby */,
rust: "overlay_analysis_code_scanning_rust" /* OverlayAnalysisCodeScanningRust */,
swift: "overlay_analysis_code_scanning_swift" /* OverlayAnalysisCodeScanningSwift */
};
var PACK_IDENTIFIER_PATTERN = (function() {
const alphaNumeric = "[a-z0-9]";
const alphaNumericDash = "[a-z0-9-]";
const component = `${alphaNumeric}(${alphaNumericDash}*${alphaNumeric})?`;
return new RegExp(`^${component}/${component}$`);
})();
function getPathToParsedConfigFile(tempDir) {
return path10.join(tempDir, "config");
}
async function getConfig(tempDir, logger) {
const configFile = getPathToParsedConfigFile(tempDir);
if (!fs8.existsSync(configFile)) {
return void 0;
}
const configString = fs8.readFileSync(configFile, "utf8");
logger.debug("Loaded config:");
logger.debug(configString);
return JSON.parse(configString);
}
function appendExtraQueryExclusions(extraQueryExclusions, cliConfig) {
const augmentedConfig = cloneObject(cliConfig);
if (extraQueryExclusions.length === 0) {
return augmentedConfig;
}
augmentedConfig["query-filters"] = [
// Ordering matters. If the first filter is an inclusion, it implicitly
// excludes all queries that are not included. If it is an exclusion,
// it implicitly includes all queries that are not excluded. So user
// filters (if any) should always be first to preserve intent.
...augmentedConfig["query-filters"] || [],
...extraQueryExclusions
];
if (augmentedConfig["query-filters"]?.length === 0) {
delete augmentedConfig["query-filters"];
}
return augmentedConfig;
}
// src/status-report.ts
function isFirstPartyAnalysis(actionName) {
if (actionName !== "upload-sarif" /* UploadSarif */) {
return true;
@@ -89599,12 +89703,12 @@ function getActionsStatus(error2, otherFailureCause) {
}
function setJobStatusIfUnsuccessful(actionStatus) {
if (actionStatus === "user-error") {
core8.exportVariable(
core9.exportVariable(
"CODEQL_ACTION_JOB_STATUS" /* JOB_STATUS */,
process.env["CODEQL_ACTION_JOB_STATUS" /* JOB_STATUS */] ?? "JOB_STATUS_CONFIGURATION_ERROR" /* ConfigErrorStatus */
);
} else if (actionStatus === "failure" || actionStatus === "aborted") {
core8.exportVariable(
core9.exportVariable(
"CODEQL_ACTION_JOB_STATUS" /* JOB_STATUS */,
process.env["CODEQL_ACTION_JOB_STATUS" /* JOB_STATUS */] ?? "JOB_STATUS_FAILURE" /* FailureStatus */
);
@@ -89623,14 +89727,14 @@ async function createStatusReportBase(actionName, status, actionStartedAt, confi
let workflowStartedAt = process.env["CODEQL_WORKFLOW_STARTED_AT" /* WORKFLOW_STARTED_AT */];
if (workflowStartedAt === void 0) {
workflowStartedAt = actionStartedAt.toISOString();
core8.exportVariable("CODEQL_WORKFLOW_STARTED_AT" /* WORKFLOW_STARTED_AT */, workflowStartedAt);
core9.exportVariable("CODEQL_WORKFLOW_STARTED_AT" /* WORKFLOW_STARTED_AT */, workflowStartedAt);
}
const runnerOs = getRequiredEnvParam("RUNNER_OS");
const codeQlCliVersion = getCachedCodeQlVersion();
const actionRef = process.env["GITHUB_ACTION_REF"] || "";
const testingEnvironment = getTestingEnvironment();
if (testingEnvironment) {
core8.exportVariable("CODEQL_ACTION_TESTING_ENVIRONMENT" /* TESTING_ENVIRONMENT */, testingEnvironment);
core9.exportVariable("CODEQL_ACTION_TESTING_ENVIRONMENT" /* TESTING_ENVIRONMENT */, testingEnvironment);
}
const isSteadyStateDefaultSetupRun = process.env["CODE_SCANNING_IS_STEADY_STATE_DEFAULT_SETUP"] === "true";
const statusReport = {
@@ -89708,9 +89812,9 @@ var INCOMPATIBLE_MSG = "CodeQL Action version is incompatible with the code scan
async function sendStatusReport(statusReport) {
setJobStatusIfUnsuccessful(statusReport.status);
const statusReportJSON = JSON.stringify(statusReport);
core8.debug(`Sending status report: ${statusReportJSON}`);
core9.debug(`Sending status report: ${statusReportJSON}`);
if (isInTestMode()) {
core8.debug("In test mode. Status reports are not uploaded.");
core9.debug("In test mode. Status reports are not uploaded.");
return;
}
const nwo = getRepositoryNwo();
@@ -89729,26 +89833,26 @@ async function sendStatusReport(statusReport) {
switch (e.status) {
case 403:
if (getWorkflowEventName() === "push" && process.env["GITHUB_ACTOR"] === "dependabot[bot]") {
core8.warning(
core9.warning(
`Workflows triggered by Dependabot on the "push" event run with read-only access. Uploading Code Scanning results requires write access. To use Code Scanning with Dependabot, please ensure you are using the "pull_request" event for this workflow and avoid triggering on the "push" event for Dependabot branches. See ${"https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning#scanning-on-push" /* SCANNING_ON_PUSH */} for more information on how to configure these events.`
);
} else {
core8.warning(e.message);
core9.warning(e.message);
}
return;
case 404:
core8.warning(e.message);
core9.warning(e.message);
return;
case 422:
if (getRequiredEnvParam("GITHUB_SERVER_URL") !== GITHUB_DOTCOM_URL) {
core8.debug(INCOMPATIBLE_MSG);
core9.debug(INCOMPATIBLE_MSG);
} else {
core8.debug(OUT_OF_DATE_MSG);
core9.debug(OUT_OF_DATE_MSG);
}
return;
}
}
core8.warning(
core9.warning(
`An unexpected error occurred when sending code scanning status report: ${getErrorMessage(
e
)}`
@@ -90007,108 +90111,6 @@ function wrapCliConfigurationError(cliError) {
return new ConfigurationError(errorMessageBuilder);
}
// src/config-utils.ts
var fs8 = __toESM(require("fs"));
var path10 = __toESM(require("path"));
var semver4 = __toESM(require_semver2());
// src/analyses.ts
var AnalysisKind = /* @__PURE__ */ ((AnalysisKind2) => {
AnalysisKind2["CodeScanning"] = "code-scanning";
AnalysisKind2["CodeQuality"] = "code-quality";
return AnalysisKind2;
})(AnalysisKind || {});
var supportedAnalysisKinds = new Set(Object.values(AnalysisKind));
// src/caching-utils.ts
var core9 = __toESM(require_core());
// src/diff-informed-analysis-utils.ts
var fs7 = __toESM(require("fs"));
var path9 = __toESM(require("path"));
function getDiffRangesJsonFilePath() {
return path9.join(getTemporaryDirectory(), "pr-diff-range.json");
}
function readDiffRangesJsonFile(logger) {
const jsonFilePath = getDiffRangesJsonFilePath();
if (!fs7.existsSync(jsonFilePath)) {
logger.debug(`Diff ranges JSON file does not exist at ${jsonFilePath}`);
return void 0;
}
const jsonContents = fs7.readFileSync(jsonFilePath, "utf8");
logger.debug(
`Read pr-diff-range JSON file from ${jsonFilePath}:
${jsonContents}`
);
return JSON.parse(jsonContents);
}
// src/trap-caching.ts
var actionsCache2 = __toESM(require_cache3());
// src/config-utils.ts
var OVERLAY_ANALYSIS_FEATURES = {
actions: "overlay_analysis_actions" /* OverlayAnalysisActions */,
cpp: "overlay_analysis_cpp" /* OverlayAnalysisCpp */,
csharp: "overlay_analysis_csharp" /* OverlayAnalysisCsharp */,
go: "overlay_analysis_go" /* OverlayAnalysisGo */,
java: "overlay_analysis_java" /* OverlayAnalysisJava */,
javascript: "overlay_analysis_javascript" /* OverlayAnalysisJavascript */,
python: "overlay_analysis_python" /* OverlayAnalysisPython */,
ruby: "overlay_analysis_ruby" /* OverlayAnalysisRuby */,
rust: "overlay_analysis_rust" /* OverlayAnalysisRust */,
swift: "overlay_analysis_swift" /* OverlayAnalysisSwift */
};
var OVERLAY_ANALYSIS_CODE_SCANNING_FEATURES = {
actions: "overlay_analysis_code_scanning_actions" /* OverlayAnalysisCodeScanningActions */,
cpp: "overlay_analysis_code_scanning_cpp" /* OverlayAnalysisCodeScanningCpp */,
csharp: "overlay_analysis_code_scanning_csharp" /* OverlayAnalysisCodeScanningCsharp */,
go: "overlay_analysis_code_scanning_go" /* OverlayAnalysisCodeScanningGo */,
java: "overlay_analysis_code_scanning_java" /* OverlayAnalysisCodeScanningJava */,
javascript: "overlay_analysis_code_scanning_javascript" /* OverlayAnalysisCodeScanningJavascript */,
python: "overlay_analysis_code_scanning_python" /* OverlayAnalysisCodeScanningPython */,
ruby: "overlay_analysis_code_scanning_ruby" /* OverlayAnalysisCodeScanningRuby */,
rust: "overlay_analysis_code_scanning_rust" /* OverlayAnalysisCodeScanningRust */,
swift: "overlay_analysis_code_scanning_swift" /* OverlayAnalysisCodeScanningSwift */
};
var PACK_IDENTIFIER_PATTERN = (function() {
const alphaNumeric = "[a-z0-9]";
const alphaNumericDash = "[a-z0-9-]";
const component = `${alphaNumeric}(${alphaNumericDash}*${alphaNumeric})?`;
return new RegExp(`^${component}/${component}$`);
})();
function getPathToParsedConfigFile(tempDir) {
return path10.join(tempDir, "config");
}
async function getConfig(tempDir, logger) {
const configFile = getPathToParsedConfigFile(tempDir);
if (!fs8.existsSync(configFile)) {
return void 0;
}
const configString = fs8.readFileSync(configFile, "utf8");
logger.debug("Loaded config:");
logger.debug(configString);
return JSON.parse(configString);
}
function appendExtraQueryExclusions(extraQueryExclusions, cliConfig) {
const augmentedConfig = cloneObject(cliConfig);
if (extraQueryExclusions.length === 0) {
return augmentedConfig;
}
augmentedConfig["query-filters"] = [
// Ordering matters. If the first filter is an inclusion, it implicitly
// excludes all queries that are not included. If it is an exclusion,
// it implicitly includes all queries that are not excluded. So user
// filters (if any) should always be first to preserve intent.
...augmentedConfig["query-filters"] || [],
...extraQueryExclusions
];
if (augmentedConfig["query-filters"]?.length === 0) {
delete augmentedConfig["query-filters"];
}
return augmentedConfig;
}
// src/setup-codeql.ts
var fs11 = __toESM(require("fs"));
var path12 = __toESM(require("path"));

View File

@@ -53,6 +53,7 @@ import {
ActionName,
InitStatusReport,
InitWithConfigStatusReport,
createInitWithConfigStatusReport,
createStatusReportBase,
getActionsStatus,
sendStatusReport,
@@ -138,65 +139,17 @@ async function sendCompletedStatusReport(
}
if (config !== undefined) {
const languages = config.languages.join(",");
const paths = (config.originalUserInput.paths || []).join(",");
const pathsIgnore = (config.originalUserInput["paths-ignore"] || []).join(
",",
);
const disableDefaultQueries = config.originalUserInput[
"disable-default-queries"
]
? languages
: "";
const queries: string[] = [];
let queriesInput = getOptionalInput("queries")?.trim();
if (queriesInput === undefined || queriesInput.startsWith("+")) {
queries.push(
...(config.originalUserInput.queries || []).map((q) => q.uses),
);
}
if (queriesInput !== undefined) {
queriesInput = queriesInput.startsWith("+")
? queriesInput.slice(1)
: queriesInput;
queries.push(...queriesInput.split(","));
}
let packs: Record<string, string[]> = {};
if (Array.isArray(config.computedConfig.packs)) {
packs[config.languages[0]] = config.computedConfig.packs;
} else if (config.computedConfig.packs !== undefined) {
packs = config.computedConfig.packs;
}
// Append fields that are dependent on `config`
const initWithConfigStatusReport: InitWithConfigStatusReport = {
...initStatusReport,
config_file: configFile ?? "",
disable_default_queries: disableDefaultQueries,
paths,
paths_ignore: pathsIgnore,
queries: queries.join(","),
packs: JSON.stringify(packs),
trap_cache_languages: Object.keys(config.trapCaches).join(","),
trap_cache_download_size_bytes: Math.round(
await getTotalCacheSize(Object.values(config.trapCaches), logger),
),
trap_cache_download_duration_ms: Math.round(config.trapCacheDownloadTime),
overlay_base_database_download_size_bytes:
overlayBaseDatabaseStats?.databaseSizeBytes,
overlay_base_database_download_duration_ms:
overlayBaseDatabaseStats?.databaseDownloadDurationMs,
query_filters: JSON.stringify(
config.originalUserInput["query-filters"] ?? [],
),
registries: JSON.stringify(
configUtils.parseRegistriesWithoutCredentials(
getOptionalInput("registries"),
) ?? [],
),
};
const initWithConfigStatusReport: InitWithConfigStatusReport =
await createInitWithConfigStatusReport(
config,
initStatusReport,
configFile,
Math.round(
await getTotalCacheSize(Object.values(config.trapCaches), logger),
),
overlayBaseDatabaseStats,
);
await sendStatusReport({
...initWithConfigStatusReport,
...initToolsDownloadFields,

View File

@@ -12,11 +12,12 @@ import {
isSelfHostedRunner,
} from "./actions-util";
import { getAnalysisKey, getApiClient } from "./api-client";
import { type Config } from "./config-utils";
import { parseRegistriesWithoutCredentials, type Config } from "./config-utils";
import { DocUrl } from "./doc-url";
import { EnvVar } from "./environment";
import { getRef } from "./git-utils";
import { Logger } from "./logging";
import { OverlayBaseDatabaseDownloadStats } from "./overlay-database-utils";
import { getRepositoryNwo } from "./repository";
import { ToolsSource } from "./setup-codeql";
import {
@@ -504,3 +505,76 @@ export interface InitWithConfigStatusReport extends InitStatusReport {
/** Path to the specified code scanning config file, from the 'config-file' config field. */
config_file: string;
}
/**
* Composes a `InitWithConfigStatusReport` from the given values.
*
* @param config The CodeQL Action configuration whose values should be added to the base status report.
* @param initStatusReport The base status report.
* @param configFile Optionally, the filename of the configuration file that was read.
* @param totalCacheSize The computed total TRAP cache size.
* @param overlayBaseDatabaseStats Statistics about the overlay database, if any.
* @returns
*/
export async function createInitWithConfigStatusReport(
config: Config,
initStatusReport: InitStatusReport,
configFile: string | undefined,
totalCacheSize: number,
overlayBaseDatabaseStats: OverlayBaseDatabaseDownloadStats | undefined,
): Promise<InitWithConfigStatusReport> {
const languages = config.languages.join(",");
const paths = (config.originalUserInput.paths || []).join(",");
const pathsIgnore = (config.originalUserInput["paths-ignore"] || []).join(
",",
);
const disableDefaultQueries = config.originalUserInput[
"disable-default-queries"
]
? languages
: "";
const queries: string[] = [];
let queriesInput = getOptionalInput("queries")?.trim();
if (queriesInput === undefined || queriesInput.startsWith("+")) {
queries.push(
...(config.originalUserInput.queries || []).map((q) => q.uses),
);
}
if (queriesInput !== undefined) {
queriesInput = queriesInput.startsWith("+")
? queriesInput.slice(1)
: queriesInput;
queries.push(...queriesInput.split(","));
}
let packs: Record<string, string[]> = {};
if (Array.isArray(config.computedConfig.packs)) {
packs[config.languages[0]] = config.computedConfig.packs;
} else if (config.computedConfig.packs !== undefined) {
packs = config.computedConfig.packs;
}
return {
...initStatusReport,
config_file: configFile ?? "",
disable_default_queries: disableDefaultQueries,
paths,
paths_ignore: pathsIgnore,
queries: queries.join(","),
packs: JSON.stringify(packs),
trap_cache_languages: Object.keys(config.trapCaches).join(","),
trap_cache_download_size_bytes: totalCacheSize,
trap_cache_download_duration_ms: Math.round(config.trapCacheDownloadTime),
overlay_base_database_download_size_bytes:
overlayBaseDatabaseStats?.databaseSizeBytes,
overlay_base_database_download_duration_ms:
overlayBaseDatabaseStats?.databaseDownloadDurationMs,
query_filters: JSON.stringify(
config.originalUserInput["query-filters"] ?? [],
),
registries: JSON.stringify(
parseRegistriesWithoutCredentials(getOptionalInput("registries")) ?? [],
),
};
}