From 832236e770b7d216fb8adb248d244afea6318607 Mon Sep 17 00:00:00 2001 From: Nicolas Vuillamy Date: Wed, 9 Aug 2023 22:50:06 +0200 Subject: [PATCH] mega-linter-runner --codetotal (#2877) * runner v0 * Allow to run CodeTotal with a single command npx mega-linter-runner@beta --codetotal * Manage browser open * Add codetotal-url option * Add colors in messages * changelog * changelog * cspell ! * [MegaLinter] Apply linters fixes --------- Co-authored-by: nvuillam Co-authored-by: nvuillam --- .cspell.json | 1 + CHANGELOG.md | 7 +- docs/reporters/GitHubCommentReporter.md | 12 +-- mega-linter-runner/lib/ascii.js | 29 +++++- mega-linter-runner/lib/codetotal.js | 114 ++++++++++++++++++++++++ mega-linter-runner/lib/options.js | 11 +++ mega-linter-runner/lib/runner.js | 7 ++ 7 files changed, 171 insertions(+), 10 deletions(-) create mode 100644 mega-linter-runner/lib/codetotal.js diff --git a/.cspell.json b/.cspell.json index 2855d07354a..3cffb178833 100644 --- a/.cspell.json +++ b/.cspell.json @@ -587,6 +587,7 @@ "codebases", "codeclimate", "codecov", + "codetotal", "codenarcargs", "codeql", "codestyle", diff --git a/CHANGELOG.md b/CHANGELOG.md index 875d147ecd6..2be47c2933e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,13 +11,14 @@ Note: Can be used with `oxsecurity/megalinter@beta` in your GitHub Action mega-l - Features - Allow to define linter_key**_COMMAND_REMOVE_ARGUMENTS** to remove a command line argument internally added by MegaLinter -- Redis reporter - - Return URL of linter icons when available, in property `iconPngUrl` - - Fixes - Replace `https://megalinter.io/config-file` by `https://megalinter.io/latest/config-file` to avoid lychee 404 detection - Improve docs for posting comments to PRs in GitHub Enterprise +- CodeTotal + - Redis reporter: Return URL of linter icons when available, in property `iconPngUrl` + - Allow to run CodeTotal with a single command `npx mega-linter-runner@beta --codetotal` , that opens CodeTotal in Web Browser once started + - Linter versions upgrades - [cfn-lint](https://github.com/aws-cloudformation/cfn-lint) from 0.79.2 to **0.79.3** on 2023-07-26 - [bicep_linter](https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/linter) from 0.19.5 to **0.20.4** on 2023-08-03 diff --git a/docs/reporters/GitHubCommentReporter.md b/docs/reporters/GitHubCommentReporter.md index f148c060a04..ccd9b28d1ad 100644 --- a/docs/reporters/GitHubCommentReporter.md +++ b/docs/reporters/GitHubCommentReporter.md @@ -15,10 +15,10 @@ Click on hyperlinks to access detailed logs ## Configuration -| Variable | Description | Default value | Notes | -|-------------------------|-------------------------------------------------------------------------------------------|--------------------------|----------| -| GITHUB_COMMENT_REPORTER | Activates/deactivates reporter | true | | +| Variable | Description | Default value | Notes | +|-------------------------|-------------------------------------------------------------------------------------------|--------------------------|----------------------------------------------| +| GITHUB_COMMENT_REPORTER | Activates/deactivates reporter | true | | | GITHUB_API_URL | URL where the github API can be reached
Must be overridden if using GitHub Enterprise | `https://api.github.com` | For GHE, use `https://my.company.com/api/v3` | -| GITHUB_SERVER_URL | URL of the GitHub instance
Must be overridden if using GitHub Enterprise | `https://github.com` | | -| CI_ACTION_RUN_URL | URL of the CI job visualization page url (if using Github but not GitHub Actions) | | | -| REPORTERS_MARKDOWN_TYPE | Set to `simple` to avoid external images in generated markdown | `advanced` | | \ No newline at end of file +| GITHUB_SERVER_URL | URL of the GitHub instance
Must be overridden if using GitHub Enterprise | `https://github.com` | | +| CI_ACTION_RUN_URL | URL of the CI job visualization page url (if using Github but not GitHub Actions) | | | +| REPORTERS_MARKDOWN_TYPE | Set to `simple` to avoid external images in generated markdown | `advanced` | | \ No newline at end of file diff --git a/mega-linter-runner/lib/ascii.js b/mega-linter-runner/lib/ascii.js index 8fe826896ac..5be123e0568 100644 --- a/mega-linter-runner/lib/ascii.js +++ b/mega-linter-runner/lib/ascii.js @@ -25,4 +25,31 @@ function asciiArt() { `; } -module.exports = { asciiArt }; +function asciiArtCodeTotal() { + return ` + .:oool' ,looo; + .xNXNXl .dXNNXo. + lXXXX0c. 'oKXXN0; + .oKNXNX0kxdddddddoc,. .;lodddddddxk0XXXX0c + .:kKXXXXXXXXXXXXNXX0dllx0XXXXXXXXXXXXXXXKd, + .,cdkOOOOOOOO0KXXXXXXXXXXK0OOOOOOOkxo:' + 'ckKXNNNXkc' + ':::::;. .c0XX0l. .;::::;. + 'xXXXXXx' :kx: ;OXXXXKd. + .dKNNXXO; .. :0XXXXKl. + .lKXXXX0: .lKXXXX0: + :0XXXXKl. .dXXXXXk, + ;kXXXXKd:cxXXXXXx' + 'xXNXXXXXXXXXKo. + .oKXXXXNXXX0l. + .lKNNXNNXO: + ,looool' + +========================================================== +============= CodeTotal, by OX Security ============== +============= https://codetotal.io =============== +========================================================== +`; +} + +module.exports = { asciiArt, asciiArtCodeTotal }; diff --git a/mega-linter-runner/lib/codetotal.js b/mega-linter-runner/lib/codetotal.js new file mode 100644 index 00000000000..c9088a1a1c6 --- /dev/null +++ b/mega-linter-runner/lib/codetotal.js @@ -0,0 +1,114 @@ +#! /usr/bin/env node +"use strict"; +const { spawnSync, spawn } = require("child_process"); +const c = require("chalk"); +const fs = require("fs-extra"); +const https = require('https'); +const open = require("open"); +const path = require("path"); +const which = require("which"); +const { asciiArtCodeTotal } = require("./ascii"); + +class CodeTotalRunner { + constructor(options = {}) { + this.options = options; + } + + async run() { + console.log(asciiArtCodeTotal()); + + // Retrieve docker-compose + if (!fs.existsSync(path.join(process.cwd(), 'docker-compose.yml'))) { + const dockerComposeUrl = "https://raw.githubusercontent.com/oxsecurity/codetotal/main/docker-compose.yml"; + console.info(c.cyan(`Downloading latest docker-compose.yml from ${c.bold(dockerComposeUrl)} ...`)); + https.get(dockerComposeUrl, resp => resp.pipe(fs.createWriteStream(path.join(process.cwd(), 'docker-compose.yml')))); + await new Promise(r => setTimeout(r, 2000)); + } + + // Check for docker installation + const whichPromise = which("docker"); + whichPromise.catch(() => { + console.error(c.red(` + ERROR: Docker engine has not been found on your system. + - to run CodeTotal locally, please install docker desktop: https://www.docker.com/products/docker-desktop`)); + }); + + // Get platform to use with docker pull & run + const imagesPlatform = this.options.platform || "linux/amd64"; + const platformVars = { + "DOCKER_DEFAULT_PLATFORM": imagesPlatform + }; + + // Pull docker image + if (this.options.nodockerpull !== true) { + console.info(c.cyan(`Pulling docker-compose.yml images...`)); + console.info(c.grey( + "INFO: this operation can be long during the first use of CodeTotal" + )); + console.info(c.grey( + "The next runs, it will be immediate (thanks to docker cache !)" + )); + console.log("Running command: " + c.whiteBright(c.bgGray("docker-compose " + ["-f", "docker-compose.yml", "pull"].join(" ")))); + const spawnResPull = spawnSync( + "docker-compose", + ["-f", "docker-compose.yml", "pull"], + { + detached: false, + stdio: "inherit", + windowsHide: true, + windowsVerbatimArguments: true, + env: { ...process.env, ...platformVars } + } + ); + // Manage case when unable to pull docker image + if (spawnResPull.status !== 0) { + return { + status: 2, + errorMsg: `Unable to pull docker images: \n${JSON.stringify( + spawnResPull, + null, + 2 + )}`, + }; + } + } else { + console.log(`Skipped pull of docker images (--nodockerpull used)`); + } + + // Prepare docker-compose command + const commandArgs = ["-f", "docker-compose.yml", "up"]; + + // Prepare interval to check localhost is open + let isOpen = false; + const uiUrl = this.options["codetotal-url"] || "http://localhost:8081/"; + let interval = setInterval(async () => { + let response; + try { + response = await fetch(uiUrl); + } catch (e) { + // URL not available yet + return; + } + const statusCode = response.status; + if (statusCode >= 200 && statusCode <= 400 && isOpen === false) { + clearInterval(interval); + isOpen = true; + console.log(c.green("CodeTotal is started: opening " + uiUrl + " ...")); + open(uiUrl); + console.log(c.yellow("Hit CTRL+C to terminate")); + } + }, 2000); + + // Call docker run + console.log("Running command: " + c.whiteBright(c.bgGray("docker-compose " + commandArgs.join(" ")))); + const spawnOptions = { + stdio: "inherit", + windowsHide: true, + env: { ...process.env, ...platformVars } + }; + const spawnRes = spawn("docker-compose", commandArgs, spawnOptions); + return spawnRes; + } +} + +module.exports = { CodeTotalRunner }; diff --git a/mega-linter-runner/lib/options.js b/mega-linter-runner/lib/options.js index e368551b5cc..18b4f2e8c10 100644 --- a/mega-linter-runner/lib/options.js +++ b/mega-linter-runner/lib/options.js @@ -141,6 +141,17 @@ module.exports = optionator({ type: "Boolean", description: "Remove MegaLinter Docker container when done", }, + { + option: "codetotal", + type: "Boolean", + description: "Run CodeTotal locally", + }, + { + option: "codetotal-url", + type: "String", + default: "http://localhost:8081/", + description: "URL Hosting CodeTotal once launched", + }, ], mutuallyExclusive: [ ["help", "version", "install"], diff --git a/mega-linter-runner/lib/runner.js b/mega-linter-runner/lib/runner.js index baa6fd7ed9e..5a08733bb1f 100644 --- a/mega-linter-runner/lib/runner.js +++ b/mega-linter-runner/lib/runner.js @@ -7,6 +7,7 @@ const path = require("path"); const which = require("which"); const fs = require("fs-extra"); const { MegaLinterUpgrader } = require("./upgrade"); +const { CodeTotalRunner} = require("./codetotal"); const { DEFAULT_RELEASE } = require("./config"); class MegaLinterRunner { @@ -59,6 +60,12 @@ class MegaLinterRunner { return { status: 0 }; } + if (options.codetotal) { + const codeTotalRunner = new CodeTotalRunner(options); + await codeTotalRunner.run(); + return {status: 0 } + } + // Build MegaLinter docker image name with flavor and release version const release = options.release in ["stable"] ? DEFAULT_RELEASE : options.release; const dockerImageName =