Fix some security issues by replacing `axios` and `request` with NodeJS
builtin `fetch`. It does requires NodeJS v18 though. Also bumping
- TypeScript version to ~5.4.5, 
- xml2js version to ^0.6.2, 
- nodemon version to ^3.1.0
- eslint version to v8
This commit is contained in:
Jeremy Meng 2024-04-16 12:20:09 -07:00 коммит произвёл GitHub
Родитель 109f60ef14
Коммит c4d7e61df7
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
10 изменённых файлов: 1551 добавлений и 8847 удалений

Просмотреть файл

@ -1,7 +1,6 @@
root: true
plugins:
- "@typescript-eslint"
- prettier
- import
- unicorn
env:
@ -27,5 +26,4 @@ rules:
order: "asc"
caseInsensitive: true
unicorn/filename-case: warn
prettier/prettier: warn
parser: "@typescript-eslint/parser"

10305
package-lock.json сгенерированный

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -31,14 +31,13 @@
"prepack": "npm run build",
"format": "npm run -s prettier -- --write",
"check-format": "npm run -s prettier -- --check",
"prettier": "prettier --config ./.prettierrc.yml **/*.{ts,js,cjs,mjs,json,yml,yaml,md}",
"prettier": "prettier --config ./.prettierrc.yml '**/*.{ts,js,cjs,mjs,json,yml,yaml,md}'",
"validate-spec-coverage": "node ./dist/cli/cli.js validate-spec-coverage --maxErrorCount=77"
},
"engines": {
"node": ">=10"
"node": ">=18"
},
"devDependencies": {
"@types/axios": "^0.14.0",
"@types/body-parser": "^1.19.2",
"@types/busboy": "^1.5.0",
"@types/commonmark": "^0.27.5",
@ -51,29 +50,26 @@
"@types/js-yaml": "^4.0.5",
"@types/morgan": "^1.9.3",
"@types/mustache": "^4.1.2",
"@types/node": "~16.9.6",
"@types/request-promise-native": "^1.0.18",
"@types/node": "^18.0.0",
"@types/supertest": "^2.0.10",
"@types/xml2js": "^0.4.9",
"@types/yargs": "^17.0.8",
"@typescript-eslint/eslint-plugin": "^4.33.0",
"@typescript-eslint/parser": "^4.33.0",
"@typescript-eslint/eslint-plugin": "^7.7.0",
"@typescript-eslint/parser": "^7.7.0",
"concurrently": "^6.5.1",
"eslint": "^7.32.0",
"eslint-plugin-import": "~2.24.2",
"eslint-plugin-prettier": "~4.0.0",
"eslint-plugin-unicorn": "~36.0.0",
"eslint": "^8.0.0",
"eslint-plugin-import": "~2.29.1",
"eslint-plugin-unicorn": "~52.0.0",
"jest": "^29.6.2",
"nodemon": "^2.0.15",
"prettier": "~2.4.1",
"nodemon": "^3.1.0",
"prettier": "~3.2.5",
"rimraf": "^3.0.2",
"supertest": "^6.2.2",
"ts-jest": "^29.1.1",
"typescript": "^4.5.4"
"typescript": "~5.4.5"
},
"dependencies": {
"@azure/storage-blob": "^12.11.0",
"axios": "^0.21.4",
"body-parser": "^1.19.1",
"busboy": "^1.6.0",
"commonmark": "^0.30.0",
@ -84,12 +80,10 @@
"js-yaml": "~4.1.0",
"morgan": "^1.10.0",
"mustache": "^4.1.0",
"request": "^2.87.0",
"request-promise-native": "^1.0.5",
"source-map-support": "^0.5.21",
"underscore": "^1.13.2",
"winston": "^3.3.4",
"xml2js": "^0.5.0",
"xml2js": "^0.6.2",
"yargs": "^17.3.1"
}
}

Просмотреть файл

@ -7,7 +7,11 @@ export class ValidationError extends Error {
* @param expected expected value.
* @param actual actual value.
*/
constructor(message: string, public expected: unknown | undefined, public actual: unknown | undefined) {
constructor(
message: string,
public expected: unknown | undefined,
public actual: unknown | undefined,
) {
super(message);
}

Просмотреть файл

@ -1,4 +1,3 @@
import axios from "axios";
import { AdminUrls } from "../../constants";
import { logger } from "../../logger";
import { CliConfig } from "../cli-config";
@ -7,7 +6,9 @@ export const stopCommand = async ({ port }: CliConfig): Promise<void> => {
logger.info("Stopping server at port {port}", port);
try {
const url = `http://localhost:${port}${AdminUrls.stop}`;
const response = await axios.post(url);
const response = await fetch(url, {
method: "POST",
});
logger.debug(`Call success: ${url} ${response.status}`);
logger.info(`Successfuly stopped server at port ${port}`);
process.exit(0);

Просмотреть файл

@ -1,6 +1,3 @@
import { RequestAPI } from "request";
import { defaults } from "request-promise-native";
export interface Comment {
id: number;
message: string;
@ -10,20 +7,22 @@ export interface Comment {
export class GitHubCiClient {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
private request: RequestAPI<any, any, any>;
private headersInit: Record<string, string> = {
"User-Agent": "AutoRest CI",
};
constructor(private githubRepo: string, githubTokenOfCI: string) {
this.request = defaults({
headers: {
"User-Agent": "AutoRest CI",
"Authorization": "token " + githubTokenOfCI,
},
});
constructor(
private githubRepo: string,
githubTokenOfCI: string,
) {
this.headersInit["Authorization"] = "token " + githubTokenOfCI;
}
public async getComments(pr: number): Promise<Comment[]> {
const res = await this.request.get(`https://api.github.com/repos/${this.githubRepo}/issues/${pr}/comments`);
const comments = JSON.parse(res);
const res = await fetch(`https://api.github.com/repos/${this.githubRepo}/issues/${pr}/comments`, {
headers: this.headersInit,
});
const comments = JSON.parse(await res.text());
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return comments.map((x: any) => {
return { id: x.id, message: x.body, user: x.user.login, url: x.html_url };
@ -35,13 +34,18 @@ export class GitHubCiClient {
}
public async setComment(id: number, message: string): Promise<void> {
await this.request.post(`https://api.github.com/repos/${this.githubRepo}/issues/comments/${id}`, {
await fetch(`https://api.github.com/repos/${this.githubRepo}/issues/comments/${id}`, {
body: JSON.stringify({ body: message }),
headers: this.headersInit,
method: "POST",
});
}
public async deleteComment(id: number): Promise<void> {
await this.request.delete(`https://api.github.com/repos/${this.githubRepo}/issues/comments/${id}`);
await fetch(`https://api.github.com/repos/${this.githubRepo}/issues/comments/${id}`, {
headers: this.headersInit,
method: "DELETE",
});
}
public async tryDeleteComment(id: number): Promise<void> {
@ -53,9 +57,11 @@ export class GitHubCiClient {
}
public async createComment(pr: number, message: string): Promise<number> {
const res = await this.request.post(`https://api.github.com/repos/${this.githubRepo}/issues/${pr}/comments`, {
const res = await fetch(`https://api.github.com/repos/${this.githubRepo}/issues/${pr}/comments`, {
body: JSON.stringify({ body: message }),
headers: this.headersInit,
method: "POST",
});
return JSON.parse(res).id;
return JSON.parse(await res.text()).id;
}
}

Просмотреть файл

@ -12,4 +12,4 @@ router.post(AdminUrls.stop, (_req, res) => {
});
});
export const adminRoutes = router;
export const adminRoutes: Router = router;

Просмотреть файл

@ -2,7 +2,7 @@ import { Router } from "express";
import { coverageService } from "../services";
const router = Router();
export const coverageRouter = router;
export const coverageRouter: Router = router;
router.post("/report/clear", (_req, res) => {
coverageService.reset();

Просмотреть файл

@ -6,4 +6,4 @@ const router = Router();
router.use("/", adminRoutes);
router.use("/", coverageRouter);
export const internalRouter = router;
export const internalRouter: Router = router;

Просмотреть файл

@ -16,8 +16,8 @@ const errorHandler: ErrorRequestHandler = (err, _req, res, _next) => {
const errResponse = err.toJSON
? err.toJSON()
: err instanceof Error
? { name: err.name, message: err.message, stack: err.stack }
: err;
? { name: err.name, message: err.message, stack: err.stack }
: err;
res.status(err.status || 500);
res.contentType("application/json").send(errResponse).end();