From ea5ccd971eaceb998b68566d29df74ae3c215187 Mon Sep 17 00:00:00 2001
From: celogeek <65178+celogeek@users.noreply.github.com>
Date: Wed, 11 May 2022 12:15:49 +0200
Subject: [PATCH] init project

---
 .gitignore   |   1 +
 index.js     | 110 +++++++++++++++++++++++++++++++++++++++++++++++++++
 package.json |  18 +++++++++
 yarn.lock    |  15 +++++++
 4 files changed, 144 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 index.js
 create mode 100644 package.json
 create mode 100644 yarn.lock

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3c3629e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+node_modules
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..9cafea2
--- /dev/null
+++ b/index.js
@@ -0,0 +1,110 @@
+const fs = require('fs');
+const split = require('split');
+
+if (!fs.existsSync('yarn.lock')) {
+  console.error('yarn.lock is missing');
+  process.exit(1);
+}
+
+function parseYarnLock() {
+  let pos = 0;
+  let currentModule = '';
+  const yarnLock = {};
+  for (const row of fs.readFileSync('yarn.lock', 'utf8').split('\n')) {
+    pos++;
+    if (row.length > 0 && row[0] != ' ') {
+      currentModule = row.replace(/"/g, '').replace(/(..*?)@.*/, '$1');
+    }
+    if (new RegExp(' +version').test(row)) {
+      const version = row.replace(/\s+version "(.*)"/, '$1');
+      if (!yarnLock[currentModule]) yarnLock[currentModule] = {};
+      yarnLock[currentModule][version] = {
+        'startLine': pos,
+        'endLine': pos,
+        'startColumn': 1,
+        'endColumn': row.length,
+      };
+    }
+  }
+  return yarnLock;
+}
+
+function yarnLockRange(yarnLock, moduleName, version) {
+  if (yarnLock[moduleName] && yarnLock[moduleName][version]) {
+    return yarnLock[moduleName][version];
+  } else {
+    return {
+      'startLine': 1,
+    };
+  }
+}
+
+const yarnLock = parseYarnLock();
+
+const severities = {
+  info: 'INFO',
+  low: 'MINOR',
+  moderate: 'MINOR',
+  high: 'CRITICAL',
+  critical: 'BLOCKER',
+};
+
+const resolvedIds = new Set();
+const stats = {};
+let firstLine = true;
+
+function processRow(row) {
+  if (!row) return;
+  const {type, data} = JSON.parse(row);
+  if (type !== 'auditAdvisory') return;
+  const {advisory, resolution} = data;
+  if (resolvedIds.has(resolution.id)) return;
+
+  const [mainVersion, ...otherVersions] = new Set(advisory.findings.map((f) => f.version));
+
+  if (!firstLine) {
+    process.stdout.write(',');
+  } else {
+    firstLine = false;
+  }
+  process.stdout.write(JSON.stringify({
+    engineId: 'yarn-audit',
+    ruleId: resolution.id.toString(),
+    severity: severities[advisory.severity] || 'INFO',
+    type: 'VULNERABILITY',
+    efforMinutes: 0,
+    primaryLocation: {
+      'message': advisory.overview,
+      'filePath': 'yarn.lock',
+      'textRange': yarnLockRange(yarnLock, advisory.module_name, mainVersion),
+    },
+    secondaryLocations: otherVersions.map((version) => {
+      return {
+        'message': advisory.overview,
+        'filePath': 'yarn.lock',
+        'textRange': yarnLockRange(yarnLock, advisory.module_name, version),
+      };
+    }),
+  }));
+  stats[advisory.severity] = (stats[advisory.severity] || 0) + 1;
+}
+
+process.stdout.write('{"issues":[');
+process
+  .stdin
+  .pipe(split())
+  .on('data', processRow)
+  .on('end', () => {
+    process.stdout.write(']}\n');
+    const out = [];
+    let total = 0;
+    for(const [k,v] of Object.entries(stats)) {
+      out.push(`${v} ${k}`);
+      total += v;
+    }
+    console.error('yarn audit:');
+    console.error(`  ${total} vulnerabilities found`);
+    if (total > 0) {
+      console.error(`  Severity: ${out.join(' | ')}`);
+    }
+  });
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..a38e89a
--- /dev/null
+++ b/package.json
@@ -0,0 +1,18 @@
+{
+  "name": "yarn-audit-sonar",
+  "version": "1.0.0",
+  "description": "Convert YARN audit to Sonar compatible format",
+  "main": "index.js",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "repository": {
+    "type": "git",
+    "url": "ssh://gitea@gitssh.celogeek.com:10026/celogeek/yarn-audit-sonar.git"
+  },
+  "author": "Celogeek",
+  "license": "ISC",
+  "dependencies": {
+    "split": "^1.0.1"
+  }
+}
diff --git a/yarn.lock b/yarn.lock
new file mode 100644
index 0000000..870d719
--- /dev/null
+++ b/yarn.lock
@@ -0,0 +1,15 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+split@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9"
+  integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==
+  dependencies:
+    through "2"
+
+through@2:
+  version "2.3.8"
+  resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
+  integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=