mobbdev 0.0.8 → 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.mjs CHANGED
@@ -5,7 +5,7 @@ const tmpObj = tmp.dirSync({
5
5
  unsafeCleanup: true,
6
6
  });
7
7
 
8
- main(tmpObj.name, process.argv.at(2))
8
+ main(tmpObj.name, process.argv[2])
9
9
  .catch((err) => {
10
10
  console.error(
11
11
  'Something went wrong, please try again or contact support if issue persists.'
package/package.json CHANGED
@@ -1,46 +1,47 @@
1
1
  {
2
- "name": "mobbdev",
3
- "version": "0.0.8",
4
- "description": "Automated secure code remediation tool",
5
- "main": "index.js",
6
- "bin": {
7
- "mobbdev": "bin/cli.mjs"
8
- },
9
- "author": "",
10
- "license": "MIT",
11
- "dependencies": {
12
- "colors": "1.4.0",
13
- "configstore": "6.0.0",
14
- "dotenv": "16.0.3",
15
- "extract-zip": "2.0.1",
16
- "form-data": "4.0.0",
17
- "got": "12.6.0",
18
- "open": "8.4.2",
19
- "snyk": "1.1118.0",
20
- "tmp": "0.2.1",
21
- "zod": "3.21.4"
22
- },
23
- "devDependencies": {
24
- "@jest/globals": "29.5.0",
25
- "eslint": "8.36.0",
26
- "jest": "29.5.0",
27
- "prettier": "2.8.4"
28
- },
29
- "engines": {
30
- "node": ">=8.5.0"
31
- },
32
- "files": [
33
- "bin",
34
- "src",
35
- "index.mjs",
36
- ".env",
37
- "README.md",
38
- "LICENSE",
39
- "package.json"
40
- ],
41
- "scripts": {
42
- "lint": "prettier --check . && eslint **/*.mjs",
43
- "lint:fix": "prettier --write . && eslint --fix **/*.mjs",
44
- "test": "DOTENV_ME=${ENV_VAULT_CLI} dotenv-vault pull development .env && TOKEN=$(../../scripts/login_auth0.sh) NODE_OPTIONS=--experimental-vm-modules jest"
45
- }
46
- }
2
+ "name": "mobbdev",
3
+ "version": "0.0.10",
4
+ "description": "Automated secure code remediation tool",
5
+ "main": "index.mjs",
6
+ "scripts": {
7
+ "lint": "prettier --check . && eslint **/*.mjs",
8
+ "lint:fix": "prettier --write . && eslint --fix **/*.mjs",
9
+ "test": "DOTENV_ME=${ENV_VAULT_CLI} dotenv-vault pull development .env && TOKEN=$(../../scripts/login_auth0.sh) NODE_OPTIONS=--experimental-vm-modules jest",
10
+ "prepack": "dotenv-vault pull production .env"
11
+ },
12
+ "bin": {
13
+ "mobbdev": "bin/cli.mjs"
14
+ },
15
+ "author": "",
16
+ "license": "MIT",
17
+ "dependencies": {
18
+ "colors": "1.4.0",
19
+ "configstore": "6.0.0",
20
+ "dotenv": "16.0.3",
21
+ "extract-zip": "2.0.1",
22
+ "node-fetch": "3.3.1",
23
+ "open": "8.4.2",
24
+ "semver": "7.5.0",
25
+ "snyk": "1.1118.0",
26
+ "tmp": "0.2.1",
27
+ "zod": "3.21.4"
28
+ },
29
+ "devDependencies": {
30
+ "@jest/globals": "29.5.0",
31
+ "eslint": "8.36.0",
32
+ "jest": "29.5.0",
33
+ "prettier": "2.8.4"
34
+ },
35
+ "engines": {
36
+ "node": ">=12.20.0"
37
+ },
38
+ "type": "module",
39
+ "files": [
40
+ "bin",
41
+ "src",
42
+ ".env",
43
+ "README.md",
44
+ "LICENSE",
45
+ "package.json"
46
+ ]
47
+ }
package/src/github.mjs CHANGED
@@ -1,9 +1,9 @@
1
- import got from 'got';
2
1
  import fs from 'node:fs';
3
- import { promisify } from 'node:util';
4
2
  import stream from 'node:stream';
5
- import extract from 'extract-zip';
6
3
  import path from 'node:path';
4
+ import { promisify } from 'node:util';
5
+ import fetch from 'node-fetch';
6
+ import extract from 'extract-zip';
7
7
 
8
8
  const pipeline = promisify(stream.pipeline);
9
9
 
@@ -18,44 +18,37 @@ export async function getDefaultBranch(repoUrl) {
18
18
  slug = slug.substring(0, slug.length - '.git'.length);
19
19
  }
20
20
 
21
- try {
22
- const repoInfo = await got(`https://api.github.com/repos/${slug}`, {
23
- method: 'GET',
24
- headers: {
25
- Accept: 'application/vnd.github+json',
26
- 'X-GitHub-Api-Version': '2022-11-28',
27
- },
28
- }).json();
29
-
30
- return repoInfo.default_branch;
31
- } catch (e) {
21
+ const response = await fetch(`https://api.github.com/repos/${slug}`, {
22
+ method: 'GET',
23
+ headers: {
24
+ Accept: 'application/vnd.github+json',
25
+ 'X-GitHub-Api-Version': '2022-11-28',
26
+ },
27
+ });
28
+
29
+ if (!response.ok) {
32
30
  throw new Error(
33
31
  `Can't get default branch, make sure the repository is public: ${repoUrl}.`
34
32
  );
35
33
  }
34
+
35
+ const repoInfo = await response.json();
36
+
37
+ return repoInfo.default_branch;
36
38
  }
37
39
 
38
40
  export async function downloadRepo(repoUrl, reference, dirname) {
39
41
  const zipFilePath = path.join(dirname, 'repo.zip');
40
- const downloadStream = got.stream(`${repoUrl}/zipball/${reference}`);
42
+ const response = await fetch(`${repoUrl}/zipball/${reference}`);
41
43
  const fileWriterStream = fs.createWriteStream(zipFilePath);
42
44
 
43
- downloadStream.on('downloadProgress', ({ transferred, percent }) => {
44
- if (transferred > 0) {
45
- console.log(
46
- `Progress: ${transferred} (${Math.round(percent * 100)}%) ...`
47
- );
48
- }
49
- });
50
-
51
- await pipeline(downloadStream, fileWriterStream);
45
+ await pipeline(response.body, fileWriterStream);
52
46
  await extract(zipFilePath, { dir: dirname });
53
47
 
54
48
  const repoRoot = fs
55
49
  .readdirSync(dirname, { withFileTypes: true })
56
50
  .filter((dirent) => dirent.isDirectory())
57
- .map((dirent) => dirent.name)
58
- .at(0);
51
+ .map((dirent) => dirent.name)[0];
59
52
 
60
53
  return path.join(dirname, repoRoot);
61
54
  }
package/src/gql.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import got from 'got';
1
+ import fetch from 'node-fetch';
2
2
  import { API_URL } from './constants.mjs';
3
3
 
4
4
  const ME = `
@@ -48,40 +48,44 @@ mutation SubmitVulnerabilityReport($vulnerabilityReportFileName: String!, $fixRe
48
48
  `;
49
49
 
50
50
  export class GQLClient {
51
- #token;
52
-
53
51
  constructor(token) {
54
- this.#token = token;
52
+ this._token = token;
55
53
  }
56
54
 
57
- async #apiCall(query, variables = {}) {
58
- const response = await got(API_URL, {
55
+ async _apiCall(query, variables = {}) {
56
+ const response = await fetch(API_URL, {
59
57
  method: 'POST',
60
58
  headers: {
61
- authorization: `Bearer ${this.#token}`,
59
+ authorization: `Bearer ${this._token}`,
62
60
  },
63
61
  body: JSON.stringify({
64
62
  query,
65
63
  variables,
66
64
  }),
67
- }).json();
65
+ });
66
+
67
+ if (!response.ok) {
68
+ throw new Error(`API call failed: ${response.status}`);
69
+ }
70
+
71
+ const data = await response.json();
68
72
 
69
- if (response.errors) {
73
+ if (data.errors) {
70
74
  throw new Error(`API error: ${response.errors[0].message}`);
71
75
  }
72
76
 
73
- if (!response.data) {
77
+ if (!data.data) {
74
78
  throw new Error('No data returned for the API query.');
75
79
  }
76
80
 
77
- return response.data;
81
+ return data.data;
78
82
  }
79
83
 
80
84
  async verifyToken() {
81
85
  await this.createCommunityUser();
82
86
 
83
87
  try {
84
- await this.#apiCall(ME);
88
+ await this._apiCall(ME);
85
89
  } catch (e) {
86
90
  return false;
87
91
  }
@@ -90,14 +94,14 @@ export class GQLClient {
90
94
 
91
95
  async createCommunityUser() {
92
96
  try {
93
- await this.#apiCall(CREATE_COMMUNITY_USER);
97
+ await this._apiCall(CREATE_COMMUNITY_USER);
94
98
  } catch (e) {
95
99
  // Ignore errors
96
100
  }
97
101
  }
98
102
 
99
103
  async uploadS3BucketInfo() {
100
- const data = await this.#apiCall(UPLOAD_S3_BUCKET_INFO, {
104
+ const data = await this._apiCall(UPLOAD_S3_BUCKET_INFO, {
101
105
  fileName: 'report.json',
102
106
  });
103
107
 
@@ -112,7 +116,7 @@ export class GQLClient {
112
116
  }
113
117
 
114
118
  async submitVulnerabilityReport(fixReportId, repoUrl, reference) {
115
- await this.#apiCall(SUBMIT_VULNERABILITY_REPORT, {
119
+ await this._apiCall(SUBMIT_VULNERABILITY_REPORT, {
116
120
  fixReportId,
117
121
  repoUrl,
118
122
  reference,
package/src/index.mjs CHANGED
@@ -1,6 +1,7 @@
1
1
  import { fileURLToPath } from 'node:url';
2
2
  import fs from 'node:fs';
3
3
  import path from 'node:path';
4
+ import semver from 'semver';
4
5
  import open from 'open';
5
6
  import Configstore from 'configstore';
6
7
  import { GQLClient } from './gql.mjs';
@@ -14,6 +15,14 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
14
15
  const packageJson = JSON.parse(
15
16
  fs.readFileSync(path.join(__dirname, '../package.json'), 'utf8')
16
17
  );
18
+
19
+ if (!semver.satisfies(process.version, packageJson.engines.node)) {
20
+ console.error(
21
+ `${packageJson.name} requires node version ${packageJson.engines.node}, but running ${process.version}.`
22
+ );
23
+ process.exit(1);
24
+ }
25
+
17
26
  const config = new Configstore(packageJson.name, { token: '' });
18
27
 
19
28
  export async function main(dirname, repoUrl) {
@@ -54,11 +63,6 @@ export async function main(dirname, repoUrl) {
54
63
 
55
64
  const report = JSON.parse(fs.readFileSync(reportPath, 'utf8'));
56
65
 
57
- if ((report.runs?.at(0)?.results?.length ?? 0) === 0) {
58
- console.log('Snyk has not found any vulnerabilities — nothing to fix.');
59
- return;
60
- }
61
-
62
66
  await uploadFile(
63
67
  reportPath,
64
68
  uploadData.url,
@@ -71,8 +75,13 @@ export async function main(dirname, repoUrl) {
71
75
  reference
72
76
  );
73
77
 
74
- console.log(
75
- 'You will be redirected to our report page, please wait until the analysis is finished and enjoy your fixes.'
76
- );
77
- await open(`${WEB_REPORT_URL}${uploadData.fixReportId}`);
78
+ const results = ((report.runs || [])[0] || {}).results || [];
79
+ if (results.length === 0) {
80
+ console.log('Snyk has not found any vulnerabilities — nothing to fix.');
81
+ } else {
82
+ console.log(
83
+ 'You will be redirected to our report page, please wait until the analysis is finished and enjoy your fixes.'
84
+ );
85
+ await open(`${WEB_REPORT_URL}${uploadData.fixReportId}`);
86
+ }
78
87
  }
@@ -1,6 +1,4 @@
1
- import FormData from 'form-data';
2
- import fs from 'node:fs';
3
- import got from 'got';
1
+ import fetch, { FormData, fileFrom } from 'node-fetch';
4
2
 
5
3
  export async function uploadFile(reportPath, url, uploadKey, uploadFields) {
6
4
  const form = new FormData();
@@ -10,10 +8,14 @@ export async function uploadFile(reportPath, url, uploadKey, uploadFields) {
10
8
  }
11
9
 
12
10
  form.append('key', uploadKey);
13
- form.append('file', fs.createReadStream(reportPath));
11
+ form.append('file', await fileFrom(reportPath));
14
12
 
15
- await got(url, {
13
+ const response = await fetch(url, {
16
14
  method: 'POST',
17
15
  body: form,
18
16
  });
17
+
18
+ if (!response.ok) {
19
+ throw new Error(`Failed to upload the report: ${response.status}`);
20
+ }
19
21
  }