From 05d540cb1148feca21022b233bea82faedebbf98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6ran=20Sander?= Date: Tue, 30 Jan 2024 13:38:18 +0000 Subject: [PATCH 1/3] build: Upgrade CodeQL scanner to v3 ... --- .github/workflows/codeql-analysis.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yaml b/.github/workflows/codeql-analysis.yaml index c8b12e6a..ec42c880 100644 --- a/.github/workflows/codeql-analysis.yaml +++ b/.github/workflows/codeql-analysis.yaml @@ -44,7 +44,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -55,7 +55,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v2 + uses: github/codeql-action/autobuild@v3 # ℹī¸ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -69,4 +69,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 From 568aa2eeb3997bf2d5c344cd3313c1e8d42c5d06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6ran=20Sander?= Date: Tue, 30 Jan 2024 13:39:44 +0000 Subject: [PATCH 2/3] fix: Make path resoultion for QIX schema files more robust ... --- package.json | 3 ++- src/app.js | 8 ++++++ src/globals.js | 32 +++++++++++++++++------ src/routes/sense_app.js | 49 ++++++++++++++++++++--------------- src/routes/sense_app_dump.js | 47 ++++++++++++++++++++------------- src/routes/sense_list_apps.js | 49 +++++++++++++++++++++-------------- 6 files changed, 121 insertions(+), 67 deletions(-) diff --git a/package.json b/package.json index ab6b63e3..15817163 100644 --- a/package.json +++ b/package.json @@ -120,7 +120,8 @@ "node_modules/fsevents/fsevents.node", "../docs/api_doc/butler-api.yaml", "node_modules/@fastify/swagger", - "static/**/*" + "static/**/*", + "package.json" ], "scripts": [ "node_modules/enigma.js/**/*.json", diff --git a/src/app.js b/src/app.js index 814beb09..61b8a4d0 100644 --- a/src/app.js +++ b/src/app.js @@ -41,12 +41,20 @@ async function build(opts = {}) { } // Load certificates to use when connecting to healthcheck API + // When running in packaged app (using pkg): import.meta.url = /snapshot/butler/build.cjs + // When running as Node.js: import.meta.url = /home/goran/code/butler/src/app.js const filename = fileURLToPath(import.meta.url); const dirname = path.dirname(filename); const certFile = path.resolve(dirname, globals.config.get('Butler.cert.clientCert')); const keyFile = path.resolve(dirname, globals.config.get('Butler.cert.clientCertKey')); const caFile = path.resolve(dirname, globals.config.get('Butler.cert.clientCertCA')); + globals.logger.verbose(`MAIN: Executing JS filename: ${filename}`); + globals.logger.verbose(`MAIN: Executing JS dirname: ${dirname}`); + globals.logger.verbose(`MAIN: Using client cert file: ${certFile}`); + globals.logger.verbose(`MAIN: Using client cert key file: ${keyFile}`); + globals.logger.verbose(`MAIN: Using client cert CA file: ${caFile}`); + // Set up heartbeats, if enabled in the config file if ( (globals.config.has('Butler.heartbeat.enabled') && globals.config.get('Butler.heartbeat.enabled') === true) || diff --git a/src/globals.js b/src/globals.js index a8ce8376..0a023ef7 100644 --- a/src/globals.js +++ b/src/globals.js @@ -25,16 +25,32 @@ class Settings { // Get app version from package.json file const filename = `./package.json`; - // const a = upath.resolve(filename) - const b = readFileSync(filename); - // const b = readFileSync(a); - const { version } = JSON.parse(b); + let a; + let b; + let c; + // Are we running as a packaged app? + if (process.pkg) { + // Get path to JS file + a = process.pkg.defaultEntrypoint; + + // Strip off the filename + b = upath.dirname(a); + + // Add path to package.json file + c = upath.join(b, filename); + } else { + // Get path to JS file + a = fileURLToPath(import.meta.url); - // const loadJSON = (path) => JSON.parse(fs.readFileSync(new URL(path, import.meta.url))); - // const { version } = loadJSON('../package.json'); - this.appVersion = version; + // Strip off the filename + b = upath.dirname(a); - console.log(`appVersion: ${this.appVersion}`); + // Add path to package.json file + c = upath.join(b, '..', filename); + } + + const { version } = JSON.parse(readFileSync(c)); + this.appVersion = version; // Command line parameters const program = new Command(); diff --git a/src/routes/sense_app.js b/src/routes/sense_app.js index 9d8753b5..753ae256 100644 --- a/src/routes/sense_app.js +++ b/src/routes/sense_app.js @@ -2,8 +2,8 @@ import httpErrors from 'http-errors'; import enigma from 'enigma.js'; import SenseUtilities from 'enigma.js/sense-utilities.js'; import WebSocket from 'ws'; -// import { createRequire } from "module"; -import { readFile } from 'fs/promises'; +import { readFileSync } from 'fs'; +import { fileURLToPath } from 'url'; import upath from 'upath'; @@ -14,31 +14,38 @@ import senseStartTask from '../qrs_util/sense_start_task.js'; import { logRESTCall } from '../lib/log_rest_call.js'; import apiPutAppReload from '../api/sense_app.js'; -// Set up enigma.js configuration - async function handlerPutAppReload(request, reply) { try { + // Set up enigma.js configuration const schemaFile = `./node_modules/enigma.js/schemas/${globals.configEngine.engineVersion}.json`; - // const require = createRequire(import.meta.url); - // // eslint-disable-next-line import/no-dynamic-require - // const qixSchema = require(schemaFile); - - // Convert schemaFile to absolute path using path - const a = upath.resolve(schemaFile) - const b = await readFile(schemaFile); - const qixSchema = JSON.parse(b); - + let a; + let b; + let c; + // Are we running as a packaged app? + if (process.pkg) { + // Yes, we are running as a packaged app + // Get path to JS file const + a = process.pkg.defaultEntrypoint; + + // Strip off the filename + b = upath.dirname(a); + + // Add path to package.json file + c = upath.join(b, schemaFile); + } else { + // No, we are running as native Node.js + // Get path to JS file + a = fileURLToPath(import.meta.url); - // const qixSchema = JSON.parse( - // await readFile( - // // new URL(schemaFile, import.meta.url); - // new URL(schemaFile, import.meta.url); - // ) - // ); + // Strip off the filename + b = upath.dirname(a); - // const { createRequire } = require('node:module'); - // const qixSchema = createRequire(schemaFile); + // Add path to package.json file + c = upath.join(b, '..', '..', schemaFile); + } + globals.logger.verbose(`APPDUMP: Using engine schema in file: ${c}`); + const qixSchema = JSON.parse(readFileSync(c)); logRESTCall(request); diff --git a/src/routes/sense_app_dump.js b/src/routes/sense_app_dump.js index 283b0505..d823fc1f 100644 --- a/src/routes/sense_app_dump.js +++ b/src/routes/sense_app_dump.js @@ -2,35 +2,46 @@ import serializeApp from 'serializeapp'; import httpErrors from 'http-errors'; import enigma from 'enigma.js'; import WebSocket from 'ws'; -// import { createRequire } from "module"; -import { readFile } from 'fs/promises'; +import { readFileSync } from 'fs'; +import { fileURLToPath } from 'url'; import upath from 'upath'; - import globals from '../globals.js'; import { logRESTCall } from '../lib/log_rest_call.js'; import { apiGetSenseAppDump, apiGetAppDump } from '../api/sense_app_dump.js'; -// Set up enigma.js configuration - async function handlerGetSenseAppDump(request, reply) { try { + // Set up enigma.js configuration const schemaFile = `./node_modules/enigma.js/schemas/${globals.configEngine.engineVersion}.json`; + let a; + let b; + let c; + // Are we running as a packaged app? + if (process.pkg) { + // Yes, we are running as a packaged app + // Get path to JS file const + a = process.pkg.defaultEntrypoint; + + // Strip off the filename + b = upath.dirname(a); + + // Add path to package.json file + c = upath.join(b, schemaFile); + } else { + // No, we are running as native Node.js + // Get path to JS file + a = fileURLToPath(import.meta.url); + // Strip off the filename + b = upath.dirname(a); - // const require = createRequire(import.meta.url); - // // eslint-disable-next-line import/no-dynamic-require - // const qixSchema = require(schemaFile); - - - // Convert schemaFile to absolute path using path - const a = upath.resolve(schemaFile) - const b = await readFile(a); - const qixSchema = JSON.parse(b); - + // Add path to package.json file + c = upath.join(b, '..', '..', schemaFile); + } - // const { createRequire } = require('node:module'); - // const qixSchema = createRequire(schemaFile); + globals.logger.verbose(`APPDUMP: Using engine schema in file: ${c}`); + const qixSchema = JSON.parse(readFileSync(c)); logRESTCall(request); @@ -58,7 +69,7 @@ async function handlerGetSenseAppDump(request, reply) { const session = enigma.create(configEnigma); const global = await session.open(); - + // We can now interact with the global object, for example get the document list. // Please refer to the Engine API documentation for available methods. const app = await global.openDoc(request.params.appId, '', '', '', true); diff --git a/src/routes/sense_list_apps.js b/src/routes/sense_list_apps.js index 041cc8eb..5ab895ff 100644 --- a/src/routes/sense_list_apps.js +++ b/src/routes/sense_list_apps.js @@ -1,36 +1,47 @@ import httpErrors from 'http-errors'; import enigma from 'enigma.js'; import WebSocket from 'ws'; -import { createRequire } from "module"; -import { readFile } from 'fs/promises'; +import { readFileSync } from 'fs'; +import { fileURLToPath } from 'url'; import upath from 'upath'; // Load global variables and functions import globals from '../globals.js'; - import { logRESTCall } from '../lib/log_rest_call.js'; import { apiGetSenseListApps, apiGetAppsList } from '../api/sense_list_apps.js'; -// Set up enigma.js configuration - async function handlerGetSenseListApps(request, reply) { try { + // Set up enigma.js configuration const schemaFile = `./node_modules/enigma.js/schemas/${globals.configEngine.engineVersion}.json`; - // const require = createRequire(import.meta.url); - // // eslint-disable-next-line import/no-dynamic-require - // const qixSchema = require(schemaFile); - - // Convert schemaFile to absolute path using path - const a = upath.resolve(schemaFile) - const b = await readFile(a); - const qixSchema = JSON.parse(b); - - - - // const { createRequire } = require('node:module'); - // const qixSchema = createRequire(schemaFile); - + let a; + let b; + let c; + // Are we running as a packaged app? + if (process.pkg) { + // Yes, we are running as a packaged app + // Get path to JS file const + a = process.pkg.defaultEntrypoint; + + // Strip off the filename + b = upath.dirname(a); + + // Add path to package.json file + c = upath.join(b, schemaFile); + } else { + // No, we are running as native Node.js + // Get path to JS file + a = fileURLToPath(import.meta.url); + + // Strip off the filename + b = upath.dirname(a); + + // Add path to package.json file + c = upath.join(b, '..', '..', schemaFile); + } + globals.logger.verbose(`APPDUMP: Using engine schema in file: ${c}`); + const qixSchema = JSON.parse(readFileSync(c)); logRESTCall(request); From bb7047aea937d71b406a5ef147f2e77be44ffd01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=B6ran=20Sander?= Date: Tue, 30 Jan 2024 13:43:03 +0000 Subject: [PATCH 3/3] Linting --- src/globals.js | 8 ++++---- src/routes/sense_app.js | 3 +-- src/routes/sense_app_dump.js | 4 ++-- src/routes/sense_list_apps.js | 28 ++++++++++++++-------------- 4 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/globals.js b/src/globals.js index 0a023ef7..84d9993c 100644 --- a/src/globals.js +++ b/src/globals.js @@ -24,7 +24,7 @@ class Settings { } // Get app version from package.json file - const filename = `./package.json`; + const filenamePackage = `./package.json`; let a; let b; let c; @@ -37,7 +37,7 @@ class Settings { b = upath.dirname(a); // Add path to package.json file - c = upath.join(b, filename); + c = upath.join(b, filenamePackage); } else { // Get path to JS file a = fileURLToPath(import.meta.url); @@ -46,7 +46,7 @@ class Settings { b = upath.dirname(a); // Add path to package.json file - c = upath.join(b, '..', filename); + c = upath.join(b, '..', filenamePackage); } const { version } = JSON.parse(readFileSync(c)); @@ -669,7 +669,7 @@ class Settings { const enableInfluxdb = this.config.get('Butler.influxDb.enable'); // Ensure that InfluxDB has been created - if(this.influx === undefined) { + if (this.influx === undefined) { this.logger.error('CONFIG: InfluxDB not initialized! Possible race condition during startup of Butler. Exiting.'); process.exit(1); } diff --git a/src/routes/sense_app.js b/src/routes/sense_app.js index 753ae256..140db6df 100644 --- a/src/routes/sense_app.js +++ b/src/routes/sense_app.js @@ -6,7 +6,6 @@ import { readFileSync } from 'fs'; import { fileURLToPath } from 'url'; import upath from 'upath'; - // Load global variables and functions import globals from '../globals.js'; @@ -24,7 +23,7 @@ async function handlerPutAppReload(request, reply) { // Are we running as a packaged app? if (process.pkg) { // Yes, we are running as a packaged app - // Get path to JS file const + // Get path to JS file const a = process.pkg.defaultEntrypoint; // Strip off the filename diff --git a/src/routes/sense_app_dump.js b/src/routes/sense_app_dump.js index d823fc1f..5e7c1c7c 100644 --- a/src/routes/sense_app_dump.js +++ b/src/routes/sense_app_dump.js @@ -20,7 +20,7 @@ async function handlerGetSenseAppDump(request, reply) { // Are we running as a packaged app? if (process.pkg) { // Yes, we are running as a packaged app - // Get path to JS file const + // Get path to JS file const a = process.pkg.defaultEntrypoint; // Strip off the filename @@ -72,7 +72,7 @@ async function handlerGetSenseAppDump(request, reply) { // We can now interact with the global object, for example get the document list. // Please refer to the Engine API documentation for available methods. - const app = await global.openDoc(request.params.appId, '', '', '', true); + const app = await global.openDoc(request.params.appId, '', '', '', true); const data = await serializeApp(app); reply.type('application/json; charset=utf-8').code(200).send(JSON.stringify(data)); diff --git a/src/routes/sense_list_apps.js b/src/routes/sense_list_apps.js index 5ab895ff..8cb7d1ef 100644 --- a/src/routes/sense_list_apps.js +++ b/src/routes/sense_list_apps.js @@ -20,7 +20,7 @@ async function handlerGetSenseListApps(request, reply) { // Are we running as a packaged app? if (process.pkg) { // Yes, we are running as a packaged app - // Get path to JS file const + // Get path to JS file const a = process.pkg.defaultEntrypoint; // Strip off the filename @@ -87,19 +87,19 @@ async function handlerGetSenseListApps(request, reply) { globals.logger.error(`LISTAPPS: Error closing connection to Sense engine: ${JSON.stringify(err, null, 2)}`); reply.send(httpErrors(500, 'Failed closing connection to Sense server')); } - // .catch((error) => { - // globals.logger.error( - // `LISTAPPS: Error while opening session to Sense engine during app listing: ${JSON.stringify(error, null, 2)}` - // ); - - // try { - // session.close(); - // } catch (err) { - // globals.logger.error(`LISTAPPS: Error closing connection to Sense engine: ${JSON.stringify(err, null, 2)}`); - // } - - // reply.send(httpErrors(422, 'Failed to open session to Sense engine')); - // }); + // .catch((error) => { + // globals.logger.error( + // `LISTAPPS: Error while opening session to Sense engine during app listing: ${JSON.stringify(error, null, 2)}` + // ); + + // try { + // session.close(); + // } catch (err) { + // globals.logger.error(`LISTAPPS: Error closing connection to Sense engine: ${JSON.stringify(err, null, 2)}`); + // } + + // reply.send(httpErrors(422, 'Failed to open session to Sense engine')); + // }); } catch (err) { globals.logger.error(`LISTAPPS: getting list of Sense apps, error is: ${JSON.stringify(err, null, 2)}`); reply.send(httpErrors(500, 'Failed getting list of Sense apps'));