From 608370c630b6fdd4ed5fbbc956eb817fbc8ff271 Mon Sep 17 00:00:00 2001 From: atraversatlassian <141701698+atraversatlassian@users.noreply.github.com> Date: Fri, 15 Sep 2023 10:47:46 +1000 Subject: [PATCH] NONE Enabling more eslint rules and fixing errors (#2413) * NONE Enabling more eslint rules and fixing errors * NONE fix unit tests * NONE fix more unit tests * NONE fix lint errors from merge * Clean up jest expect rule * NONE refactor eslint file * Fix lint errors from merge * Addressing initial feedback * Addressing feedback * More careful with toString * Address feedback * Addressing feedback * minor fixes * Fix some typing --- .eslintrc.json | 100 +++++++++++------- package.json | 1 + src/app.test.ts | 4 +- src/app.ts | 2 +- src/config/jira-test-site-check.test.ts | 2 +- src/config/logger.ts | 6 +- src/config/metric-helpers.test.ts | 2 +- src/config/statsd.ts | 2 +- src/github/client/app-token-holder.ts | 2 +- src/github/client/github-anonymous-client.ts | 2 +- src/github/client/github-client-errors.ts | 2 +- .../client/github-client-interceptors.ts | 2 +- src/github/client/github-client.ts | 4 +- src/github/client/github-client.types.ts | 22 ++++ src/github/client/github-queries.ts | 1 + src/github/code-scanning-alert.test.ts | 63 ++++++++++- src/github/code-scanning-alert.ts | 9 +- src/github/installation.ts | 2 +- src/github/issue-comment.ts | 9 +- src/github/repository.ts | 2 +- src/jira/client/jira-client.ts | 6 +- src/jira/util/jira-client-util.ts | 3 +- src/jira/util/jwt.test.ts | 6 +- src/jira/util/jwt.ts | 27 ++--- src/middleware/github-webhook-middleware.ts | 6 +- .../jira-symmetric-jwt-middleware.ts | 9 +- src/models/axios-error-event-decorator.ts | 2 +- src/models/encrypted-model.test.ts | 2 +- src/models/installation.test.ts | 4 +- .../jira-admin/jira-admin-check.test.ts | 2 +- src/rest/routes/analytics-proxy/index.test.ts | 2 +- src/rest/routes/github-apps/index.test.ts | 2 +- src/rest/routes/github-orgs/index.test.ts | 2 +- src/rest/routes/jira/index.test.ts | 2 +- src/rest/routes/oauth/index.test.ts | 2 +- src/routes/api/api-router.ts | 2 +- .../api/client-key/recover-client-key.ts | 2 +- ...t-failed-and-pending-deployment-cursors.ts | 2 +- .../data-cleanup/cleanup-reposyncstates.ts | 4 +- .../api/db-migrations/db-migration-down.ts | 2 +- .../api/db-migrations/db-migration-utils.ts | 6 +- .../api/installation/api-installation-get.ts | 5 +- .../api/jira/api-jira-uninstall-post.ts | 2 +- .../github-configuration-app-installs-get.ts | 2 +- .../configuration/github-configuration-get.ts | 12 ++- .../create-branch/github-branches-get.test.ts | 2 +- .../github-create-branch-get.test.ts | 6 +- .../create-branch/github-create-branch-get.ts | 6 +- .../github-create-branch-options-get.ts | 4 +- ...github-create-branch-post.frontend.test.ts | 4 +- .../github-create-branch-post.ts | 3 +- src/routes/github/github-5ku-router.ts | 4 +- src/routes/github/github-oauth.ts | 3 +- src/routes/github/github-router.test.ts | 2 +- .../manifest/github-manifest-complete-get.ts | 2 +- src/routes/github/setup/github-setup-post.ts | 2 +- ...ithub-subscription-deferred-install-get.ts | 2 +- ...thub-subscription-deferred-install-post.ts | 2 +- .../github/webhook/webhook-receiver-post.ts | 5 +- .../jira-atlassian-connect-get.ts | 2 +- ...nnect-enterprise-app-create-or-edit-get.ts | 5 +- .../jira-connect-enterprise-app-post.test.ts | 8 +- .../app/jira-connect-enterprise-app-put.ts | 5 +- .../app/jira-connect-enterprise-apps-get.ts | 5 +- .../jira-connect-enterprise-delete.ts | 5 +- .../enterprise/jira-connect-enterprise-get.ts | 5 +- .../jira-connect-enterprise-post.ts | 12 +-- src/routes/jira/connect/jira-connect-get.ts | 5 +- .../jira/jira-connected-repos-get.test.ts | 2 +- src/routes/jira/jira-connected-repos-get.ts | 5 +- src/routes/jira/jira-delete.test.ts | 4 +- src/routes/jira/jira-get.ts | 7 +- .../jira-security-workspaces-post.test.ts | 12 +-- src/routes/version/version-get.ts | 4 +- .../subscription-installation-service.test.ts | 4 +- src/sqs/backfill-error-handler.test.ts | 2 +- src/sqs/error-handlers.ts | 13 +-- src/sqs/sqs.ts | 4 +- src/sync/branches.ts | 3 +- src/sync/code-scanning-alerts.ts | 4 +- src/sync/commits.ts | 3 +- src/sync/deduplicator.test.ts | 2 +- src/sync/dependabot-alerts.ts | 4 +- src/sync/deployment.test.ts | 29 +++-- src/sync/installation.test.ts | 2 +- src/sync/parallel-page-fetcher.test.ts | 20 ++-- src/sync/scheduler.test.ts | 10 +- src/sync/transforms/branch.ts | 6 +- src/transforms/push.ts | 2 +- .../transform-code-scanning-alert.ts | 10 +- src/transforms/transform-dependabot-alert.ts | 4 +- src/transforms/transform-deployment.test.ts | 8 +- src/transforms/transform-pull-request.ts | 2 +- src/transforms/transform-repository-id.ts | 2 +- .../transform-secret-scanning-alert.ts | 2 +- src/transforms/transform-workflow.ts | 2 +- src/util/create-url-with-query-string.ts | 3 +- src/util/curl/curl-utils.test.ts | 4 +- src/util/error-string-from-unknown.ts | 3 + src/util/handlebars/handlebar-helpers.ts | 4 +- src/util/jira-utils.test.ts | 2 +- src/util/logger-utils.ts | 2 +- src/util/workers-health-monitor.ts | 8 +- test/e2e/utils/jira.ts | 2 +- .../setup/matchers/to-be-called-with-delay.ts | 2 +- test/setup/matchers/to-promise.ts | 2 +- test/setup/setup.ts | 2 +- .../routes/api/api-router.test.ts.snap | 2 +- test/snapshots/snapshot-resolver.ts | 2 +- test/utils/database-state-creator.ts | 2 +- yarn.lock | 5 + 111 files changed, 399 insertions(+), 272 deletions(-) create mode 100644 src/util/error-string-from-unknown.ts diff --git a/.eslintrc.json b/.eslintrc.json index c8e9580a6e..dae25f8aec 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -35,11 +35,12 @@ } }, "rules": { - "@typescript-eslint/explicit-module-boundary-types": "off", - "@typescript-eslint/no-var-requires": "error", - "@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }], - "no-unused-vars": "off", - "no-console": "error", + "indent": ["error", "tab", { + "SwitchCase": 1 + }], + "@typescript-eslint/indent": ["error", "tab", { + "SwitchCase": 1 + }], "quotes": [ "error", "double", @@ -48,13 +49,7 @@ "allowTemplateLiterals": true } ], - "indent": ["error", "tab", { - "SwitchCase": 1 - }], - "@typescript-eslint/indent": ["error", "tab", { - "SwitchCase": 1 - }], - "@import/no-unresolved": "off", + //extra rules "object-curly-spacing": ["error", "always"], "semi": ["error", "always"], "no-trailing-spaces": "error", @@ -62,34 +57,17 @@ "keyword-spacing": "error", "space-in-parens": ["error", "never"], "func-style" : ["error", "expression"], - "require-await": "off", "@typescript-eslint/no-floating-promises": ["error"], - "jest/expect-expect": [ - "error", - { - "assertFunctionNames": [ - "expect", - "supertest.**.expect", - "*.expect" - ] - } - ], - // To be removed later - "@typescript-eslint/no-non-null-assertion": "off", - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/prefer-nullish-coalescing": "off", - "@typescript-eslint/restrict-template-expressions": "off", - "@typescript-eslint/no-unsafe-assignment": "off", - "@typescript-eslint/no-unsafe-argument": "off", - "@typescript-eslint/no-unsafe-member-access": "off", - "@typescript-eslint/no-unsafe-return": "off", - "@typescript-eslint/no-unsafe-call": "off", - "@typescript-eslint/unbound-method": "off", - "@typescript-eslint/require-await": "off", - "@typescript-eslint/await-thenable": "off", - "@typescript-eslint/restrict-plus-operands": "off", - "@typescript-eslint/no-misused-promises": "off" - + "@typescript-eslint/explicit-module-boundary-types": "off", + "@typescript-eslint/no-var-requires": "error", + "@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }], + "no-unused-vars": ["error", { "argsIgnorePattern": "^_" }], + "no-console": "error", + "@typescript-eslint/restrict-template-expressions": ["error", { + "allowBoolean": true, + "allowNullish": true, + "allowNumber": true + }] }, "overrides": [{ "files": [ "test/**/*.ts", "src/**/*.test.ts" ], @@ -100,7 +78,49 @@ "@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-non-null-assertion": "off", "jest/no-done-callback": "off", - "jest/expect-expect": "off" + "jest/expect-expect": [ + "error", + { + "assertFunctionNames": [ + "expect", + "supertest.**.expect", + "*.expect", + "expectDisabledButton", + "expectEnabledButton" + ] + } + ] + } + }, + { + "files": [ + "test/**", + "src/*.ts", + "src/config/**", + "src/github/**", + "src/jira/**", + "src/middleware/**", + "src/models/**", + "src/rest/**", + "src/routes/**", + "src/services/**", + "src/sqs/**", + "src/sync/**", + "src/transforms/**", + "src/util/**", + "src/worker/**" + ], + "rules": { + // To be removed later + "@typescript-eslint/no-unsafe-assignment": "off", + "@typescript-eslint/no-unsafe-argument": "off", + "@typescript-eslint/no-unsafe-member-access": "off", + "@typescript-eslint/no-unsafe-return": "off", + "@typescript-eslint/no-unsafe-call": "off", + "@typescript-eslint/unbound-method": "off", + "@typescript-eslint/require-await": "off", + "@typescript-eslint/await-thenable": "off", + "@typescript-eslint/no-misused-promises": "off" } }] } diff --git a/package.json b/package.json index 1f41798766..e1ae61f755 100644 --- a/package.json +++ b/package.json @@ -63,6 +63,7 @@ "@octokit/auth-app": "^2.6.0", "@octokit/graphql-schema": "^10.73.0", "@sentry/node": "^6.8.0", + "@types/safe-json-stringify": "^1.1.2", "atlassian-jwt": "^2.0.0", "aws-sdk": "^2.1015.0", "axios": "^0.26.0", diff --git a/src/app.test.ts b/src/app.test.ts index 7a6488f9d2..3d74e7c183 100644 --- a/src/app.test.ts +++ b/src/app.test.ts @@ -6,7 +6,7 @@ describe("app", () => { it("please review routes and update snapshot when adding or modifying the routes!", async () => { const app = getFrontendApp(); - const appRoutes: Array = []; + const appRoutes: Array<{method: string, path: string, exec: string[]}> = []; const collectRoutes = (stack, parentPath = "", parentMiddlewares: Array = []) => { const ROOT_REGEX = parentPath + sanitizeRegexStr("^\\/?(?=\\/|$)"); const pathMiddlewares = {}; @@ -51,7 +51,7 @@ describe("app", () => { collectRoutes(app._router.stack); const allRoutes = appRoutes.map(route => - ":" + route.method.toUpperCase() + " " + route.path + "\n\t" + route.exec.join(",") + `:${route.method.toUpperCase()} ${route.path}\n\t${route.exec.join(",")}` ).join("\n"); expect(allRoutes).toMatchSnapshot(); diff --git a/src/app.ts b/src/app.ts index 3019eaadf6..b3e62a4ab1 100644 --- a/src/app.ts +++ b/src/app.ts @@ -44,7 +44,7 @@ const secureHeaders = (app: Express) => { defaultSrc: ["'self'"], // Allow "; -const setupNockForXSSBranches = (gitHubInstallationId) => { +const setupNockForXSSBranches = (gitHubInstallationId: number) => { githubNock .post(`/app/installations/${gitHubInstallationId}/access_tokens`) diff --git a/src/routes/github/create-branch/github-create-branch-get.test.ts b/src/routes/github/create-branch/github-create-branch-get.test.ts index 55ab1ad1e4..cdb46f0471 100644 --- a/src/routes/github/create-branch/github-create-branch-get.test.ts +++ b/src/routes/github/create-branch/github-create-branch-get.test.ts @@ -19,12 +19,12 @@ for (let i = 0; i < 100; i++) { REPOS_FIXTURE_EXPANDED.data.viewer.repositories.edges.push({ node: { id: 1000 + i, - name: "SampleRepo" + i, - full_name: "user1/SampleRepo" + i, + name: `SampleRepo${i}`, + full_name: `user1/SampleRepo${i}`, owner: { login: "user1" }, - html_url: "https://github.com/user1/SampleRepo" + i, + html_url: `https://github.com/user1/SampleRepo${i}`, updated_at: new Date(i * 1000).toISOString() } }); diff --git a/src/routes/github/create-branch/github-create-branch-get.ts b/src/routes/github/create-branch/github-create-branch-get.ts index 072a72f85f..397382c341 100644 --- a/src/routes/github/create-branch/github-create-branch-get.ts +++ b/src/routes/github/create-branch/github-create-branch-get.ts @@ -11,10 +11,8 @@ import { RepoSyncState } from "models/reposyncstate"; const MAX_REPOS_RETURNED = 20; export const GithubCreateBranchGet = async (req: Request, res: Response, next: NextFunction): Promise => { - const { - gitHubAppConfig, - jiraHost - } = res.locals; + const gitHubAppConfig = res.locals.gitHubAppConfig; + const jiraHost: string = res.locals.jiraHost; const logger = getLogger("github-create-branch-get", { fields: { ...req.log?.fields, diff --git a/src/routes/github/create-branch/github-create-branch-options-get.ts b/src/routes/github/create-branch/github-create-branch-options-get.ts index 6f5623d54b..5100e9c634 100644 --- a/src/routes/github/create-branch/github-create-branch-options-get.ts +++ b/src/routes/github/create-branch/github-create-branch-options-get.ts @@ -16,7 +16,7 @@ export const GithubCreateBranchOptionsGet = async (req: Request, res: Response, return next(new Error(Errors.MISSING_ISSUE_KEY)); } - const jiraHost = res.locals.jiraHost; + const jiraHost: string = res.locals.jiraHost; const logger = getLogger("github-create-branch-get-options", { fields: { @@ -43,7 +43,7 @@ export const GithubCreateBranchOptionsGet = async (req: Request, res: Response, return; } - const url = new URL(`${req.protocol}://${req.get("host")}${req.originalUrl}`); + const url = new URL(`${req.protocol}://${req.get("host") ?? ""}${req.originalUrl}`); // Only has cloud instance if (servers.hasCloudServer && servers.gheServerInfos.length == 0) { logger.info("redirecting to cloud."); diff --git a/src/routes/github/create-branch/github-create-branch-post.frontend.test.ts b/src/routes/github/create-branch/github-create-branch-post.frontend.test.ts index 323c96634b..cb82f57559 100644 --- a/src/routes/github/create-branch/github-create-branch-post.frontend.test.ts +++ b/src/routes/github/create-branch/github-create-branch-post.frontend.test.ts @@ -79,7 +79,7 @@ describe("github-create-branch-post.frontend", () => { ]); }); - const expandSelector = async (text) => { + const expandSelector = async (text: string) => { const elementWithTextLocator = await page.locator(`span.select2-chosen:has-text("${text}")`); const element = await elementWithTextLocator.elementHandle(); @@ -162,6 +162,8 @@ describe("github-create-branch-post.frontend", () => { await page.click("#createBranchBtn"); await page.waitForSelector("text=Github branch created"); + + expect(gheApiNock).toBeDone(); }); }); }); diff --git a/src/routes/github/create-branch/github-create-branch-post.ts b/src/routes/github/create-branch/github-create-branch-post.ts index 0fb57864ef..dd8c2d016f 100644 --- a/src/routes/github/create-branch/github-create-branch-post.ts +++ b/src/routes/github/create-branch/github-create-branch-post.ts @@ -35,7 +35,8 @@ const getErrorMessages = (statusCode: number): string => { export const GithubCreateBranchPost = async (req: Request, res: Response): Promise => { const { gitHubAppConfig, jiraHost } = res.locals; - const { owner, repo, sourceBranchName, newBranchName } = req.body; + const { owner, repo, sourceBranchName } = req.body; + const newBranchName: string = req.body.newBranchName; const logger = getLogger("github-create-branch-options-get", { fields: req.log?.fields }); diff --git a/src/routes/github/github-5ku-router.ts b/src/routes/github/github-5ku-router.ts index ae6af9d90c..7aa8de6269 100644 --- a/src/routes/github/github-5ku-router.ts +++ b/src/routes/github/github-5ku-router.ts @@ -3,8 +3,8 @@ import sanitize from "sanitize-html"; export const GitHub5KURedirectHandler = (req: Request, res: Response, next: NextFunction) => { if (req.query["state"] === "spa") { - const sanitizedGitHubInstallationId = sanitize(String(req.query.installation_id || "")); - const sanitizedSetupAction = sanitize(String(req.query.setup_action || "")); + const sanitizedGitHubInstallationId: string = sanitize(String(req.query.installation_id || "")); + const sanitizedSetupAction: string = sanitize(String(req.query.setup_action || "")); if (sanitizedGitHubInstallationId) { res.redirect(`/rest/app/cloud/github-installed?installation_id=${sanitizedGitHubInstallationId}`); } else if (sanitizedSetupAction) { diff --git a/src/routes/github/github-oauth.ts b/src/routes/github/github-oauth.ts index 88b98b1e3c..1290c4c92c 100644 --- a/src/routes/github/github-oauth.ts +++ b/src/routes/github/github-oauth.ts @@ -33,7 +33,8 @@ const getRedirectUrl = async (res: Response, state: string) => { } const scopes = ["user", "repo"]; - const { hostname, clientId } = res.locals.gitHubAppConfig; + const hostname: string = res.locals.gitHubAppConfig.hostname; + const clientId: string = res.locals.gitHubAppConfig.clientId; const callbackURI = `${appUrl}${callbackPath}`; return `${hostname}/login/oauth/authorize?client_id=${clientId}&scope=${encodeURIComponent(scopes.join(" "))}&redirect_uri=${encodeURIComponent(callbackURI)}&state=${state}`; }; diff --git a/src/routes/github/github-router.test.ts b/src/routes/github/github-router.test.ts index 0974094b6c..584783c61d 100644 --- a/src/routes/github/github-router.test.ts +++ b/src/routes/github/github-router.test.ts @@ -181,7 +181,7 @@ describe("GitHub router", () => { .get("/github/configuration") .set( "Cookie", - `session=${cookies.session}; session.sig=${cookies["session.sig"]}` + `session=${cookies.session as string}; session.sig=${cookies["session.sig"] as string}` ) .expect(302); diff --git a/src/routes/github/manifest/github-manifest-complete-get.ts b/src/routes/github/manifest/github-manifest-complete-get.ts index 5cf67667c0..18d7f689d1 100644 --- a/src/routes/github/manifest/github-manifest-complete-get.ts +++ b/src/routes/github/manifest/github-manifest-complete-get.ts @@ -43,7 +43,7 @@ export const GithubManifestCompleteGet = async (req: Request, res: Response) => } : undefined ); - const gitHubAppConfig = await gitHubClient.createGitHubApp("" + req.query.code); + const gitHubAppConfig = await gitHubClient.createGitHubApp(req.query.code.toString()); await GitHubServerApp.install({ uuid, appId: gitHubAppConfig.id, diff --git a/src/routes/github/setup/github-setup-post.ts b/src/routes/github/setup/github-setup-post.ts index 5c6e1828b6..6f923eafbf 100644 --- a/src/routes/github/setup/github-setup-post.ts +++ b/src/routes/github/setup/github-setup-post.ts @@ -25,7 +25,7 @@ const validateJiraSite = async ( export const GithubSetupPost = async (req: Request, res: Response): Promise => { const { jiraHost, jiraDomain, jiraDomainMain, jiraDomainModal } = req.body; - const domain = jiraDomain || jiraDomainMain || jiraDomainModal || ""; + const domain: string = jiraDomain || jiraDomainMain || jiraDomainModal || ""; const url = jiraHost || `https://${domain}.atlassian.net`; req.log.debug({ jiraHost: url }, `Received github setup page request for jira`); diff --git a/src/routes/github/subscription-deferred-install/github-subscription-deferred-install-get.ts b/src/routes/github/subscription-deferred-install/github-subscription-deferred-install-get.ts index 85c6d32660..af1562ed34 100644 --- a/src/routes/github/subscription-deferred-install/github-subscription-deferred-install-get.ts +++ b/src/routes/github/subscription-deferred-install/github-subscription-deferred-install-get.ts @@ -18,7 +18,7 @@ export const GitHubSubscriptionDeferredInstallGet = async (req: Request, res: Re res.render("subscription-deferred-install-approval-form.hbs", { csrfToken: req.csrfToken(), orgName: payload.orgName, - orgUrl: `${res.locals.gitHubAppConfig.hostname}/${payload.orgName}`, + orgUrl: `${res.locals.gitHubAppConfig.hostname as string}/${payload.orgName}`, jiraHost: res.locals.jiraHost }); diff --git a/src/routes/github/subscription-deferred-install/github-subscription-deferred-install-post.ts b/src/routes/github/subscription-deferred-install/github-subscription-deferred-install-post.ts index 4462a470c3..73b2dd7ed5 100644 --- a/src/routes/github/subscription-deferred-install/github-subscription-deferred-install-post.ts +++ b/src/routes/github/subscription-deferred-install/github-subscription-deferred-install-post.ts @@ -22,7 +22,7 @@ export const GithubSubscriptionDeferredInstallPost = async (req: Request, res: R res.render("subscription-deferred-install-approval-form.hbs", { success: true, orgName: payload.orgName, - orgUrl: `${res.locals.gitHubAppConfig.hostname}/${payload.orgName}`, + orgUrl: `${res.locals.gitHubAppConfig.hostname as string}/${payload.orgName}`, jiraHost: res.locals.jiraHost }); }; diff --git a/src/routes/github/webhook/webhook-receiver-post.ts b/src/routes/github/webhook/webhook-receiver-post.ts index 4851bd65af..02f3e0c318 100644 --- a/src/routes/github/webhook/webhook-receiver-post.ts +++ b/src/routes/github/webhook/webhook-receiver-post.ts @@ -23,6 +23,7 @@ import { dependabotAlertWebhookHandler } from "~/src/github/dependabot-alert"; import { extraLoggerInfo } from "./webhook-logging-extra"; import { secretScanningAlertWebhookHandler } from "~/src/github/secret-scanning-alert"; import { installationWebhookHandler } from "~/src/github/installation"; +import { errorStringFromUnknown } from "~/src/util/error-string-from-unknown"; export const WebhookReceiverPost = async (request: Request, response: Response): Promise => { const eventName = request.headers["x-github-event"] as string; @@ -87,8 +88,8 @@ export const WebhookReceiverPost = async (request: Request, response: Response): webhookContext.log.info("Webhook was successfully processed"); response.sendStatus(204); - } catch (err) { - (webhookContext?.log || logger).error({ err }, "Something went wrong, returning 400: " + err.message); + } catch (err: unknown) { + (webhookContext?.log || logger).error({ err }, `Something went wrong, returning 400: ${errorStringFromUnknown(err)}`); response.sendStatus(400); } }; diff --git a/src/routes/jira/atlassian-connect/jira-atlassian-connect-get.ts b/src/routes/jira/atlassian-connect/jira-atlassian-connect-get.ts index 94ebcac14c..c88730fa7a 100644 --- a/src/routes/jira/atlassian-connect/jira-atlassian-connect-get.ts +++ b/src/routes/jira/atlassian-connect/jira-atlassian-connect-get.ts @@ -8,7 +8,7 @@ const isProd = instance === "production"; // TODO: implement named routes (https://www.npmjs.com/package/named-routes) to facilitate rerouting between files export const postInstallUrl = "/jira"; -export const APP_NAME = `GitHub for Jira${isProd ? "" : ` (${instance})`}`; +export const APP_NAME = `GitHub for Jira${isProd ? "" : ` (${instance ?? ""})`}`; export const LOGO_URL = "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png"; const adminCondition = [ diff --git a/src/routes/jira/connect/enterprise/app/jira-connect-enterprise-app-create-or-edit-get.ts b/src/routes/jira/connect/enterprise/app/jira-connect-enterprise-app-create-or-edit-get.ts index 4668f221b1..40fce0971a 100644 --- a/src/routes/jira/connect/enterprise/app/jira-connect-enterprise-app-create-or-edit-get.ts +++ b/src/routes/jira/connect/enterprise/app/jira-connect-enterprise-app-create-or-edit-get.ts @@ -6,6 +6,7 @@ import { sendAnalytics } from "utils/analytics-client"; import { AnalyticsEventTypes, AnalyticsScreenEventsEnum } from "interfaces/common"; import { resolveIntoConnectConfig } from "utils/ghe-connect-config-temp-storage"; import { getAllKnownHeaders } from "utils/http-headers"; +import { errorStringFromUnknown } from "~/src/util/error-string-from-unknown"; export const JiraConnectEnterpriseAppCreateOrEditGet = async ( req: Request, @@ -79,7 +80,7 @@ export const JiraConnectEnterpriseAppCreateOrEditGet = async ( knownHttpHeadersLowerCase: getAllKnownHeaders() }); req.log.debug("Jira create or edit app page rendered successfully."); - } catch (error) { - return next(new Error(`Failed to render Jira create or edit app page: ${error}`)); + } catch (error: unknown) { + return next(new Error(`Failed to render Jira create or edit app page: ${errorStringFromUnknown(error)}`)); } }; diff --git a/src/routes/jira/connect/enterprise/app/jira-connect-enterprise-app-post.test.ts b/src/routes/jira/connect/enterprise/app/jira-connect-enterprise-app-post.test.ts index ab1b5b4e3c..54f7f7132d 100644 --- a/src/routes/jira/connect/enterprise/app/jira-connect-enterprise-app-post.test.ts +++ b/src/routes/jira/connect/enterprise/app/jira-connect-enterprise-app-post.test.ts @@ -51,7 +51,7 @@ describe("jira-connect-enterprise-app-post", () => { TEST_GHE_APP_PARTIAL = { appId: 12321, gitHubBaseUrl: gheUrl, - gitHubClientId: "client-id" + Math.random(), + gitHubClientId: "client-id" + Math.random().toString(), gitHubClientSecret: "client-secret", webhookSecret: "webhook-secret", privateKey: fs.readFileSync(path.resolve(__dirname, "../../../../../../test/setup/test-key.pem"), { encoding: "utf8" }), @@ -122,9 +122,9 @@ describe("jira-connect-enterprise-app-post", () => { gitHubClientId: expect.stringMatching(/client-id.*/i), secrets: null, - privateKey: "encrypted:" + TEST_GHE_APP_PARTIAL.privateKey, - gitHubClientSecret: "encrypted:" + TEST_GHE_APP_PARTIAL.gitHubClientSecret, - webhookSecret: "encrypted:" + TEST_GHE_APP_PARTIAL.webhookSecret, + privateKey: "encrypted:" + (TEST_GHE_APP_PARTIAL.privateKey as string), + gitHubClientSecret: "encrypted:" + (TEST_GHE_APP_PARTIAL.gitHubClientSecret as string), + webhookSecret: "encrypted:" + (TEST_GHE_APP_PARTIAL.webhookSecret as string), apiKeyHeaderName: null, encryptedApiKeyValue: null, diff --git a/src/routes/jira/connect/enterprise/app/jira-connect-enterprise-app-put.ts b/src/routes/jira/connect/enterprise/app/jira-connect-enterprise-app-put.ts index 62b92e8b07..e06c4ab6ee 100644 --- a/src/routes/jira/connect/enterprise/app/jira-connect-enterprise-app-put.ts +++ b/src/routes/jira/connect/enterprise/app/jira-connect-enterprise-app-put.ts @@ -3,6 +3,7 @@ import { GitHubServerApp } from "~/src/models/github-server-app"; import { sendAnalytics } from "utils/analytics-client"; import { AnalyticsEventTypes, AnalyticsTrackEventsEnum, AnalyticsTrackSource } from "interfaces/common"; import { validateApiKeyInputsAndReturnErrorIfAny } from "utils/api-key-validator"; +import { errorStringFromUnknown } from "~/src/util/error-string-from-unknown"; export const JiraConnectEnterpriseAppPut = async ( req: Request, @@ -47,7 +48,7 @@ export const JiraConnectEnterpriseAppPut = async ( res.status(202).send(); req.log.debug("Jira Connect Enterprise App updated successfully."); - } catch (error) { + } catch (error: unknown) { await sendAnalytics(res.locals.jiraHost, AnalyticsEventTypes.TrackEvent, { action: AnalyticsTrackEventsEnum.UpdateGitHubServerAppTrackEventName, @@ -58,6 +59,6 @@ export const JiraConnectEnterpriseAppPut = async ( }); res.status(404).send({ message: "Failed to update GitHub App." }); - return next(new Error(`Failed to update GitHub app: ${error}`)); + return next(new Error(`Failed to update GitHub app: ${errorStringFromUnknown(error)}`)); } }; diff --git a/src/routes/jira/connect/enterprise/app/jira-connect-enterprise-apps-get.ts b/src/routes/jira/connect/enterprise/app/jira-connect-enterprise-apps-get.ts index db9335c310..f2d84a0328 100644 --- a/src/routes/jira/connect/enterprise/app/jira-connect-enterprise-apps-get.ts +++ b/src/routes/jira/connect/enterprise/app/jira-connect-enterprise-apps-get.ts @@ -3,6 +3,7 @@ import { GitHubServerApp } from "models/github-server-app"; import { sendAnalytics } from "utils/analytics-client"; import { AnalyticsEventTypes, AnalyticsScreenEventsEnum } from "interfaces/common"; import { resolveIntoConnectConfig } from "utils/ghe-connect-config-temp-storage"; +import { errorStringFromUnknown } from "~/src/util/error-string-from-unknown"; export const JiraConnectEnterpriseAppsGet = async ( req: Request, @@ -51,8 +52,8 @@ export const JiraConnectEnterpriseAppsGet = async ( } req.log.debug("Jira Connect Enterprise App page rendered successfully."); - } catch (error) { - return next(new Error(`Failed to render Jira Connect Enterprise App page: ${error}`)); + } catch (error: unknown) { + return next(new Error(`Failed to render Jira Connect Enterprise App page: ${errorStringFromUnknown(error)}`)); } }; diff --git a/src/routes/jira/connect/enterprise/jira-connect-enterprise-delete.ts b/src/routes/jira/connect/enterprise/jira-connect-enterprise-delete.ts index fda5fd42fa..807ba0464d 100644 --- a/src/routes/jira/connect/enterprise/jira-connect-enterprise-delete.ts +++ b/src/routes/jira/connect/enterprise/jira-connect-enterprise-delete.ts @@ -4,6 +4,7 @@ import { sendAnalytics } from "utils/analytics-client"; import { AnalyticsEventTypes, AnalyticsTrackEventsEnum, AnalyticsTrackSource } from "interfaces/common"; import { isConnected } from "utils/is-connected"; import { saveConfiguredAppProperties } from "utils/app-properties-utils"; +import { errorStringFromUnknown } from "~/src/util/error-string-from-unknown"; export const JiraConnectEnterpriseDelete = async ( req: Request, @@ -32,7 +33,7 @@ export const JiraConnectEnterpriseDelete = async ( res.status(200).send({ success: true }); req.log.debug("Jira Connect Enterprise Server successfully deleted."); - } catch (error) { + } catch (error: unknown) { await sendAnalytics(res.locals.jiraHost, AnalyticsEventTypes.TrackEvent, { action: AnalyticsTrackEventsEnum.RemoveGitHubServerTrackEventName, @@ -43,6 +44,6 @@ export const JiraConnectEnterpriseDelete = async ( }); res.status(200).send({ success: false, message: "Failed to delete GitHub Enterprise Server." }); - return next(new Error(`Failed to DELETE GitHub Enterprise Server: ${error}`)); + return next(new Error(`Failed to DELETE GitHub Enterprise Server: ${errorStringFromUnknown(error)}`)); } }; diff --git a/src/routes/jira/connect/enterprise/jira-connect-enterprise-get.ts b/src/routes/jira/connect/enterprise/jira-connect-enterprise-get.ts index e266dde895..99c3894dba 100644 --- a/src/routes/jira/connect/enterprise/jira-connect-enterprise-get.ts +++ b/src/routes/jira/connect/enterprise/jira-connect-enterprise-get.ts @@ -4,6 +4,7 @@ import { chain, groupBy } from "lodash"; import { sendAnalytics } from "utils/analytics-client"; import { AnalyticsEventTypes, AnalyticsScreenEventsEnum } from "interfaces/common"; import { getAllKnownHeaders } from "utils/http-headers"; +import { errorStringFromUnknown } from "~/src/util/error-string-from-unknown"; export const JiraConnectEnterpriseGet = async ( req: Request, @@ -40,8 +41,8 @@ export const JiraConnectEnterpriseGet = async ( } req.log.debug("Jira Connect Enterprise GET page rendered successfully."); - } catch (error) { - return next(new Error(`Failed to render Jira Connect Enterprise GET page: ${error}`)); + } catch (error: unknown) { + return next(new Error(`Failed to render Jira Connect Enterprise GET page: ${errorStringFromUnknown(error)}`)); } }; diff --git a/src/routes/jira/connect/enterprise/jira-connect-enterprise-post.ts b/src/routes/jira/connect/enterprise/jira-connect-enterprise-post.ts index 5a0f325375..058b42e585 100644 --- a/src/routes/jira/connect/enterprise/jira-connect-enterprise-post.ts +++ b/src/routes/jira/connect/enterprise/jira-connect-enterprise-post.ts @@ -69,9 +69,9 @@ export const JiraConnectEnterprisePost = async ( // inside the handler const TIMEOUT_PERIOD_MS = parseInt(process.env.JIRA_CONNECT_ENTERPRISE_POST_TIMEOUT_MSEC || "30000"); - const gheServerURL = req.body.gheServerURL?.trim(); - const apiKeyHeaderName = req.body.apiKeyHeaderName?.trim(); - const apiKeyValue = req.body.apiKeyValue?.trim(); + const gheServerURL: string = req.body.gheServerURL?.trim() ?? "undefined"; + const apiKeyHeaderName: string | undefined = req.body.apiKeyHeaderName?.trim(); + const apiKeyValue: string | undefined = req.body.apiKeyValue?.trim(); const { id: installationId } = res.locals.installation; @@ -124,7 +124,7 @@ export const JiraConnectEnterprisePost = async ( try { const client = await createAnonymousClient(gheServerURL, jiraHost, { trigger: "jira-connect-enterprise-post" }, req.log, - apiKeyHeaderName + apiKeyHeaderName && apiKeyValue !== undefined ? { headerName: apiKeyHeaderName, apiKeyGenerator: () => Promise.resolve(apiKeyValue) @@ -146,7 +146,7 @@ export const JiraConnectEnterprisePost = async ( reason: "Received OK, but the host is not GitHub Enterprise server" }] }); - sendErrorMetricAndAnalytics(jiraHost, ErrorResponseCode.CANNOT_CONNECT, "" + response.status); + sendErrorMetricAndAnalytics(jiraHost, ErrorResponseCode.CANNOT_CONNECT, response?.status?.toString() ?? "undefined"); return; } @@ -176,7 +176,7 @@ export const JiraConnectEnterprisePost = async ( return; } - const codeOrStatus = "" + (axiosError.code || axiosError.response?.status); + const codeOrStatus = (axiosError.code || axiosError.response?.status?.toString() || "undefined"); req.log.warn({ err, gheServerURL }, `Couldn't access GHE host`); const reasons = [err.message]; diff --git a/src/routes/jira/connect/jira-connect-get.ts b/src/routes/jira/connect/jira-connect-get.ts index 1bbd052dba..7c49e96320 100644 --- a/src/routes/jira/connect/jira-connect-get.ts +++ b/src/routes/jira/connect/jira-connect-get.ts @@ -1,6 +1,7 @@ import { NextFunction, Request, Response } from "express"; import { sendAnalytics } from "utils/analytics-client"; import { AnalyticsEventTypes, AnalyticsScreenEventsEnum } from "interfaces/common"; +import { errorStringFromUnknown } from "~/src/util/error-string-from-unknown"; export const JiraConnectGet = async ( req: Request, @@ -19,7 +20,7 @@ export const JiraConnectGet = async ( res.render("jira-select-github-product.hbs"); req.log.info("Jira Connect page rendered successfully."); - } catch (error) { - return next(new Error(`Failed to render Jira Connect page: ${error}`)); + } catch (error: unknown) { + return next(new Error(`Failed to render Jira Connect page: ${errorStringFromUnknown(error)}`)); } }; diff --git a/src/routes/jira/jira-connected-repos-get.test.ts b/src/routes/jira/jira-connected-repos-get.test.ts index 6682da3971..35ba654d90 100644 --- a/src/routes/jira/jira-connected-repos-get.test.ts +++ b/src/routes/jira/jira-connected-repos-get.test.ts @@ -105,7 +105,7 @@ describe("jira-connected-repos-get", () => { delete newRepoSyncState["commitStatus"]; delete newRepoSyncState["branchStatus"]; newRepoSyncState["repoId"] = repoSyncState.repoId + newRepoStateNo; - newRepoSyncState["repoName"] = repoSyncState.repoName + newRepoStateNo; + newRepoSyncState["repoName"] = repoSyncState.repoName + newRepoStateNo.toString(); newRepoSyncState["repoFullName"] = repoSyncState.repoFullName + String(newRepoStateNo).padStart(3, "0"); if (newRepoStateNo % 3 == 1) { newRepoSyncState["commitStatus"] = "complete"; diff --git a/src/routes/jira/jira-connected-repos-get.ts b/src/routes/jira/jira-connected-repos-get.ts index 16950607ec..1c848f1fbd 100644 --- a/src/routes/jira/jira-connected-repos-get.ts +++ b/src/routes/jira/jira-connected-repos-get.ts @@ -3,6 +3,7 @@ import { Op } from "sequelize"; import { RepoSyncState } from "~/src/models/reposyncstate"; import { Subscription, TaskStatus } from "~/src/models/subscription"; import { sequelize } from "models/sequelize"; +import { errorStringFromUnknown } from "~/src/util/error-string-from-unknown"; interface Page { pageNum: number; @@ -130,9 +131,9 @@ export const JiraConnectedReposGet = async ( ...getPaginationState(pageNumber, pageSize, reposCount) }); - } catch (err) { + } catch (err: unknown) { req.log.warn({ err }, "Failed to render connected repos"); - return next(new Error(`Failed to render connected repos: ${err}`)); + return next(new Error(`Failed to render connected repos: ${errorStringFromUnknown(err)}`)); } }; diff --git a/src/routes/jira/jira-delete.test.ts b/src/routes/jira/jira-delete.test.ts index f00b9f10e1..1885b62c3c 100644 --- a/src/routes/jira/jira-delete.test.ts +++ b/src/routes/jira/jira-delete.test.ts @@ -94,11 +94,11 @@ describe("DELETE /jira/configuration", () => { .reply(200, "OK"); jiraNock - .delete("/rest/security/1.0/linkedWorkspaces/bulk?workspaceIds="+subscription.id) + .delete("/rest/security/1.0/linkedWorkspaces/bulk?workspaceIds="+(subscription.id ? (subscription.id as number)?.toString() : "undefined")) .reply(202); jiraNock - .delete("/rest/security/1.0/bulkByProperties?workspaceId="+subscription.id) + .delete("/rest/security/1.0/bulkByProperties?workspaceId="+(subscription.id ? (subscription.id as number)?.toString() : "undefined")) .reply(202); jiraNock diff --git a/src/routes/jira/jira-get.ts b/src/routes/jira/jira-get.ts index d935638edc..82d8a1ab39 100644 --- a/src/routes/jira/jira-get.ts +++ b/src/routes/jira/jira-get.ts @@ -13,6 +13,7 @@ import { AnalyticsEventTypes, AnalyticsScreenEventsEnum } from "interfaces/commo import { getCloudOrServerFromGitHubAppId } from "utils/get-cloud-or-server"; import { Errors } from "config/errors"; import { booleanFlag, BooleanFlags } from "config/feature-flags"; +import { errorStringFromUnknown } from "~/src/util/error-string-from-unknown"; interface FailedConnection { id: number; @@ -182,7 +183,7 @@ const renderJiraCloudAndEnterpriseServer = async (res: Response, req: Request): } const successfulServerConnections = gheServersWithConnections - .reduce((acc, obj) => acc + obj.successfulConnections?.length, 0); + .reduce((acc: number, obj: any) => acc + (obj.successfulConnections?.length as number), 0); const allSuccessfulConnections = [...successfulCloudConnections, ...gheServersWithConnections]; const completeConnections = allSuccessfulConnections.filter(connection => connection.syncStatus === "FINISHED"); @@ -232,7 +233,7 @@ export const JiraGet = async ( await renderJiraCloudAndEnterpriseServer(res, req); req.log.debug("Jira configuration rendered successfully."); - } catch (error) { - return next(new Error(`Failed to render Jira configuration: ${error}`)); + } catch (error: unknown) { + return next(new Error(`Failed to render Jira configuration: ${errorStringFromUnknown(error)}`)); } }; diff --git a/src/routes/jira/security/workspaces/jira-security-workspaces-post.test.ts b/src/routes/jira/security/workspaces/jira-security-workspaces-post.test.ts index 40305233da..9d637448be 100644 --- a/src/routes/jira/security/workspaces/jira-security-workspaces-post.test.ts +++ b/src/routes/jira/security/workspaces/jira-security-workspaces-post.test.ts @@ -169,7 +169,7 @@ describe("Workspaces Post", () => { { id: String(createdDbEntries.sub1.id), name: createdDbEntries.repo1.repoOwner, - url: "https://github.com/"+ createdDbEntries.repo1.repoOwner, + url: "https://github.com/" + (createdDbEntries.repo1.repoOwner as string), avatarUrl: createdDbEntries.sub1.avatarUrl } ] @@ -220,7 +220,7 @@ describe("Workspaces Post", () => { { id: String(createdDbEntries.sub1.id), name: createdDbEntries.repo1.repoOwner, - url: "https://github.com/"+ createdDbEntries.repo1.repoOwner, + url: "https://github.com/" + (createdDbEntries.repo1.repoOwner as string), avatarUrl: createdDbEntries.sub1.avatarUrl } ] @@ -250,7 +250,7 @@ describe("Workspaces Post", () => { { id: String(createdDbEntries.sub3.id), name: createdDbEntries.repo3.repoOwner, - url: "https://github.com/"+ createdDbEntries.repo3.repoOwner, + url: "https://github.com/" + (createdDbEntries.repo3.repoOwner as string), avatarUrl: DEFAULT_AVATAR } ] @@ -279,19 +279,19 @@ describe("Workspaces Post", () => { { id: String(createdDbEntries.sub1.id), name: createdDbEntries.repo1.repoOwner, - url: "https://github.com/"+ createdDbEntries.repo1.repoOwner, + url: "https://github.com/" + (createdDbEntries.repo1.repoOwner as string), avatarUrl: createdDbEntries.sub1.avatarUrl }, { id: String(createdDbEntries.sub2.id), name: createdDbEntries.repo2.repoOwner, - url: "https://github.internal.atlassian.com/"+ createdDbEntries.repo2.repoOwner, + url: "https://github.internal.atlassian.com/" + (createdDbEntries.repo2.repoOwner as string), avatarUrl: createdDbEntries.sub2.avatarUrl }, { id: String(createdDbEntries.sub3.id), name: createdDbEntries.repo3.repoOwner, - url: "https://github.com/"+ createdDbEntries.repo3.repoOwner, + url: "https://github.com/" + (createdDbEntries.repo3.repoOwner as string), avatarUrl: DEFAULT_AVATAR } ] diff --git a/src/routes/version/version-get.ts b/src/routes/version/version-get.ts index 633692a4e5..eb457839ae 100644 --- a/src/routes/version/version-get.ts +++ b/src/routes/version/version-get.ts @@ -4,10 +4,10 @@ import { envVars } from "config/env"; export const VersionGet = (_: Request, res: Response) => { res.send({ branch: envVars.GIT_BRANCH_NAME, - branchUrl: `${envVars.GITHUB_REPO_URL}/tree/${envVars.GIT_BRANCH_NAME}`, + branchUrl: `${envVars.GITHUB_REPO_URL}/tree/${envVars.GIT_BRANCH_NAME ?? "undefined"}`, commit: envVars.GIT_COMMIT_SHA, commitDate: envVars.GIT_COMMIT_DATE, - commitUrl: `${envVars.GITHUB_REPO_URL}/commit/${envVars.GIT_COMMIT_SHA}`, + commitUrl: `${envVars.GITHUB_REPO_URL}/commit/${envVars.GIT_COMMIT_SHA ?? "undefined"}`, deploymentDate: envVars.DEPLOYMENT_DATE }); }; diff --git a/src/services/subscription-installation-service.test.ts b/src/services/subscription-installation-service.test.ts index 736db45e03..ed2c656a71 100644 --- a/src/services/subscription-installation-service.test.ts +++ b/src/services/subscription-installation-service.test.ts @@ -36,7 +36,7 @@ describe("subscription-installation-service", () => { if (config.isInstalledInUserSpace !== undefined) { cloudOrGheNock - .get("/app/installations/" + gitHubInstallationId) + .get("/app/installations/" + gitHubInstallationId.toString()) .matchHeader("Authorization", /^Bearer .+$/) .reply(200, { account: { @@ -48,7 +48,7 @@ describe("subscription-installation-service", () => { if (config.fetchAvatar === true) { cloudOrGheNock - .get("/app/installations/" + gitHubInstallationId) + .get("/app/installations/" + gitHubInstallationId.toString()) .matchHeader("Authorization", /^Bearer .+$/) .reply(200, { account: { diff --git a/src/sqs/backfill-error-handler.test.ts b/src/sqs/backfill-error-handler.test.ts index f49e186a30..91a02ae778 100644 --- a/src/sqs/backfill-error-handler.test.ts +++ b/src/sqs/backfill-error-handler.test.ts @@ -57,7 +57,7 @@ describe("backfillErrorHandler", () => { "date": "Fri, 04 Mar 2022 21:09:27 GMT", "x-ratelimit-limit": "8900", "x-ratelimit-remaining": "0", - "x-ratelimit-reset": "" + resetTime, + "x-ratelimit-reset": "" + resetTime.toString(), "x-ratelimit-resource": "core", "x-ratelimit-used": "2421" }); diff --git a/src/sqs/error-handlers.ts b/src/sqs/error-handlers.ts index 1cb5ab8fac..aa5bfa9b95 100644 --- a/src/sqs/error-handlers.ts +++ b/src/sqs/error-handlers.ts @@ -1,5 +1,4 @@ import { JiraClientError } from "../jira/client/axios"; -import { Octokit } from "@octokit/rest"; import { emitWebhookFailedMetrics } from "utils/webhook-utils"; import { ErrorHandler, ErrorHandlingResult, SQSMessageContext, BaseMessagePayload } from "./sqs.types"; import { GithubClientRateLimitingError } from "../github/client/github-client-errors"; @@ -18,10 +17,8 @@ const RATE_LIMITING_DELAY_BUFFER_SEC = 10; const EXPONENTIAL_BACKOFF_BASE_SEC = 60; const EXPONENTIAL_BACKOFF_MULTIPLIER = 3; -type ErrorTypes = JiraClientError | Octokit.HookError | GithubClientRateLimitingError | Error; - export const handleUnknownError: ErrorHandler = async ( - err: ErrorTypes, + err: Error, context: SQSMessageContext ): Promise => { const delaySec = EXPONENTIAL_BACKOFF_BASE_SEC * Math.pow(EXPONENTIAL_BACKOFF_MULTIPLIER, context.receiveCount); @@ -29,7 +26,7 @@ export const handleUnknownError: ErrorHandler = async = async (error: ErrorTypes, +export const jiraAndGitHubErrorsHandler: ErrorHandler = async (error: Error, context: SQSMessageContext): Promise => { context.log.warn({ err: error }, "Handling Jira or GitHub error"); @@ -78,9 +75,9 @@ const maybeHandleNonRetryableResponseCode = { const sendMessageResult = await this.sqs.sendMessage(params) .promise(); - logger.info({ delaySeconds: delaySec, newMessageId: sendMessageResult.MessageId }, `Successfully added message to sqs queue messageId: ${sendMessageResult.MessageId}`); + logger.info({ delaySeconds: delaySec, newMessageId: sendMessageResult.MessageId }, `Successfully added message to sqs queue messageId: ${sendMessageResult.MessageId ?? "undefinded"}`); statsd.increment(sqsQueueMetrics.sent, this.metricsTags, { jiraHost: payload.jiraHost }); return sendMessageResult; } @@ -382,7 +382,7 @@ export class SqsQueue { public async changeVisibilityTimeout(message: Message, timeoutSec: number, logger: Logger): Promise { if (!message.ReceiptHandle) { - logger.error(`No ReceiptHandle in message with ID = ${message.MessageId}`); + logger.error(`No ReceiptHandle in message with ID = ${message.MessageId ?? ""}`); return; } diff --git a/src/sync/branches.ts b/src/sync/branches.ts index 43e6a3b72d..3d4230cefc 100644 --- a/src/sync/branches.ts +++ b/src/sync/branches.ts @@ -5,6 +5,7 @@ import Logger from "bunyan"; import { BackfillMessagePayload } from "~/src/sqs/sqs.types"; import { createHashWithSharedSecret } from "utils/encryption"; import { shouldSendAll } from "config/feature-flags"; +import { Branch } from "~/src/github/client/github-client.types"; // TODO: better typings export const getBranchTask = async ( @@ -24,7 +25,7 @@ export const getBranchTask = async ( const commitSince = messagePayload.commitsFromDate ? new Date(messagePayload.commitsFromDate) : undefined; const result = await gitHubClient.getBranchesPage(repository.owner.login, repository.name, perPage, commitSince, cursor as string); const edges = result?.repository?.refs?.edges || []; - const branches = edges.map(edge => edge?.node); + const branches: Branch[] = edges.map(edge => edge?.node); (logger.fields || {}).branchNameArray = (branches || []).map(b => createHashWithSharedSecret(String(b.name))); (logger.fields || {}).branchShaArray = (branches || []).map(b => createHashWithSharedSecret(String(b.target?.oid))); const alwaysSendBranches = await shouldSendAll("branches-backfill", _jiraHost, logger); diff --git a/src/sync/code-scanning-alerts.ts b/src/sync/code-scanning-alerts.ts index 734eba3bf1..0b64a08ebb 100644 --- a/src/sync/code-scanning-alerts.ts +++ b/src/sync/code-scanning-alerts.ts @@ -85,8 +85,8 @@ const transformCodeScanningAlert = async ( const gitHubClientConfig = await getGitHubClientConfigFromAppId(gitHubAppId, jiraHost); - const handleUnmappedState = (state) => logger.info(`Received unmapped state from code_scanning_alert sync: ${state}`); - const handleUnmappedSeverity = (severity) => logger.info(`Received unmapped severity from code_scanning_alert sync: ${severity}`); + const handleUnmappedState = (state: string) => logger.info(`Received unmapped state from code_scanning_alert sync: ${state}`); + const handleUnmappedSeverity = (severity: string | null) => logger.info(`Received unmapped severity from code_scanning_alert sync: ${severity ?? "Missing Severity"}`); const vulnerabilities = alerts.map((alert) => { const identifiers = transformRuleTagsToIdentifiers(alert.rule.tags); diff --git a/src/sync/commits.ts b/src/sync/commits.ts index 97b359b8ad..bc0caefd05 100644 --- a/src/sync/commits.ts +++ b/src/sync/commits.ts @@ -38,7 +38,8 @@ export const getCommitTask = async ( const { edges, commits } = await fetchCommits(gitHubClient, repository, commitSince, cursor, perPage); if (commits.length > 0) { - logger.info(`Last commit authoredDate=${commits[commits.length - 1].authoredDate}`); + const authoredDate = commits[commits.length - 1]?.authoredDate; + logger.info(`Last commit authoredDate=${authoredDate?.toString() || "undefined"}`); (logger.fields || {}).commitShaArray = commits.map(c => createHashWithSharedSecret(String(c.oid))); } const alwaysSend = await shouldSendAll("commits-backfill", _jiraHost, logger); diff --git a/src/sync/deduplicator.test.ts b/src/sync/deduplicator.test.ts index f17f37674d..3ebb650ca6 100644 --- a/src/sync/deduplicator.test.ts +++ b/src/sync/deduplicator.test.ts @@ -8,7 +8,7 @@ describe("deduplicator", () => { let key = ""; beforeEach(() => { storage = new RedisInProgressStorageWithTimeout(redis); - key = new Date().toISOString() + Math.random(); + key = new Date().toISOString() + Math.random().toString(); jest.useFakeTimers("modern").setSystemTime(new Date("2020-01-01").getTime()); }); diff --git a/src/sync/dependabot-alerts.ts b/src/sync/dependabot-alerts.ts index fcdb082103..e135edf142 100644 --- a/src/sync/dependabot-alerts.ts +++ b/src/sync/dependabot-alerts.ts @@ -86,8 +86,8 @@ const transformDependabotAlerts = async ( const gitHubClientConfig = await getGitHubClientConfigFromAppId(gitHubAppId, jiraHost); - const handleUnmappedState = (state) => logger.info(`Received unmapped state from dependabot_alerts sync: ${state}`); - const handleUnmappedSeverity = (severity) => logger.info(`Received unmapped severity from dependabot_alerts sync: ${severity}`); + const handleUnmappedState = (state: string) => logger.info(`Received unmapped state from dependabot_alerts sync: ${state}`); + const handleUnmappedSeverity = (severity: string | null) => logger.info(`Received unmapped severity from dependabot_alerts sync: ${severity ?? "Missing Severity"}`); const vulnerabilities = alerts.map((alert) => { return { diff --git a/src/sync/deployment.test.ts b/src/sync/deployment.test.ts index 8e7a8a9fe6..5bb1f79ad6 100644 --- a/src/sync/deployment.test.ts +++ b/src/sync/deployment.test.ts @@ -10,7 +10,7 @@ import { envVars } from "config/env"; import deploymentNodesFixture from "fixtures/api/graphql/deployment-nodes.json"; import mixedDeploymentNodes from "fixtures/api/graphql/deployment-nodes-mixed.json"; -import { getDeploymentsQuery, getDeploymentsQueryWithStatuses } from "~/src/github/client/github-queries"; +import { DeploymentQueryNode, getDeploymentsQuery, getDeploymentsQueryWithStatuses } from "~/src/github/client/github-queries"; import { waitUntil } from "test/utils/wait-until"; import { DatabaseStateCreator } from "test/utils/database-state-creator"; import { GitHubServerApp } from "models/github-server-app"; @@ -209,16 +209,15 @@ describe("sync/deployments", () => { //size up to 9 entities const createDeploymentEntities = (size: number) => { return Array.from({ length: size }).map((_, idx) => { - const clone = JSON.parse(JSON.stringify(deploymentNodesFixture.data.repository.deployments.edges[0])); - clone._seq = idx + 1; - clone.cursor = `cursor:${idx + 1}`; + const clone: DeploymentQueryNode = JSON.parse(JSON.stringify(deploymentNodesFixture.data.repository.deployments.edges[0])); + clone.cursor = `${idx + 1}`; clone.node.createdAt = `2023-01-0${idx + 1}T10:00:00Z`; clone.node.updatedAt = `2023-01-0${idx + 1}T10:00:00Z`; clone.node.databaseId = `dbid-${idx + 1}`; clone.node.commitOid = `SHA${idx + 1}`; - clone.node.statuses.nodes.forEach(n => { + clone.node.statuses!.nodes.forEach(n => { n.createdAt = clone.node.createdAt; - n.updatedAt = clone.node.updatedAt; + n.updatedAt = clone.node.updatedAt!; if (n.state === "SUCCESS") { n.logUrl = `deployment-url-${idx + 1}`; } @@ -232,10 +231,10 @@ describe("sync/deployments", () => { .query(true).reply(200, { data: { repository: { deployments: { edges: deployments } } } }); }; - const nockDeploymentListingApi = (deployments, repeatTimes) => { + const nockDeploymentListingApi = (deployments: DeploymentQueryNode[], repeatTimes: number) => { Array.from({ length: repeatTimes }).forEach(() => { githubNock.get(`/repos/test-repo-owner/test-repo-name/deployments?environment=prod&per_page=10`) - .reply(200, deployments.map((item, idx) => ({ + .reply(200, deployments.map((item: DeploymentQueryNode, idx: number) => ({ id: item.node.databaseId, sha: item.node.commitOid, ref: "random", @@ -255,7 +254,7 @@ describe("sync/deployments", () => { }); }; - const nockDeploymentStatusApi = (deployments, repeatTimes) => { + const nockDeploymentStatusApi = (deployments: DeploymentQueryNode[], repeatTimes: number) => { Array.from({ length: repeatTimes }).forEach(() => { deployments.forEach((item, idx) => { githubNock.get(`/repos/test-repo-owner/test-repo-name/deployments/${item.node.databaseId}/statuses?per_page=100`) @@ -267,25 +266,25 @@ describe("sync/deployments", () => { }); }; - const nockDeploymentCommitGetApi = (deployments, repeatTimes) => { + const nockDeploymentCommitGetApi = (deployments: DeploymentQueryNode[], repeatTimes: number) => { Array.from({ length: repeatTimes }).forEach(() => { deployments.forEach(item => { githubNock.get(`/repos/test-repo-owner/test-repo-name/commits/${item.node.commitOid}`) .reply(200, { commit: { author: { name: "random", email: "random", date: new Date() }, - message: `commit message [JIRA-${item._seq}]` + message: `commit message [JIRA-${item.cursor}]` }, html_url: "random" }); }); }); }; - const expectDeploymentEntryInDB = async (deployments) => { + const expectDeploymentEntryInDB = async (deployments: DeploymentQueryNode[]) => { for (const deployment of deployments) { const { repository: { id: repoId }, environment, statuses, commitOid } = deployment.node; const key = createHashWithoutSharedSecret(`ghurl_${gitHubCloudConfig.baseUrl}_repo_${repoId}_env_${environment}`); - const successStatusDate = new Date(statuses.nodes.find(n=>n.state === "SUCCESS")?.updatedAt).getTime(); + const successStatusDate = new Date(statuses!.nodes.find(n=>n.state === "SUCCESS")!.updatedAt).getTime(); const result = await ddb.getItem({ TableName: envVars.DYNAMO_DEPLOYMENT_HISTORY_CACHE_TABLE_NAME, Key: { @@ -299,14 +298,14 @@ describe("sync/deployments", () => { } }; - const expectEdgesAndPayloadMatchToDeploymentCommits = (result, deployments) => { + const expectEdgesAndPayloadMatchToDeploymentCommits = (result, deployments: DeploymentQueryNode[]) => { expect(result).toEqual({ edges: deployments.map(d => expect.objectContaining({ cursor: d.cursor, node: expect.objectContaining({ commitOid: d.node.commitOid }) }) ), jiraPayload: { deployments: deployments.map(d => expect.objectContaining({ - associations: [{ associationType: "issueIdOrKeys", values: [ `JIRA-${d._seq}`] }] }) + associations: [{ associationType: "issueIdOrKeys", values: [ `JIRA-${d.cursor}`] }] }) ) } }); diff --git a/src/sync/installation.test.ts b/src/sync/installation.test.ts index ee607d3c90..e6628237e9 100644 --- a/src/sync/installation.test.ts +++ b/src/sync/installation.test.ts @@ -354,7 +354,7 @@ describe("sync/installation", () => { const sendMessageMock = jest.fn(); await markCurrentTaskAsFailedAndContinue({ ...MESSAGE_PAYLOAD, - installationId: MESSAGE_PAYLOAD.installationId + 1 + installationId: (MESSAGE_PAYLOAD.installationId as number) + 1 }, TASK, false, sendMessageMock, getLogger("test"), mockError); const refreshedRepoSyncState = await RepoSyncState.findByPk(repoSyncState.id); diff --git a/src/sync/parallel-page-fetcher.test.ts b/src/sync/parallel-page-fetcher.test.ts index 34d856d7ef..6ffbe906fb 100644 --- a/src/sync/parallel-page-fetcher.test.ts +++ b/src/sync/parallel-page-fetcher.test.ts @@ -7,11 +7,11 @@ describe("fetchNextPagesInParallel", () => { const singlePageFetchFactory = jest.fn().mockImplementation((pageCursor: PageSizeAwareCounterCursor) => { const edges = [{ cursor: pageCursor.serialise(), - node: { id: "id" + pageCursor.pageNo } + node: { id: "id" + pageCursor.pageNo.toString() } }]; const jiraPayload = { - pullRequests: [{ id: "pid" + pageCursor.pageNo }], - builds: [{ id: "bid" + pageCursor.pageNo }] + pullRequests: [{ id: "pid" + pageCursor.pageNo.toString() }], + builds: [{ id: "bid" + pageCursor.pageNo.toString() }] }; return Promise.resolve({ edges, jiraPayload }); }); @@ -33,12 +33,12 @@ describe("fetchNextPagesInParallel", () => { const singlePageFetchFactory = jest.fn().mockImplementation((pageCursor: PageSizeAwareCounterCursor) => { const edges = [{ cursor: pageCursor.serialise(), - node: { id: "id" + pageCursor.pageNo } + node: { id: "id" + pageCursor.pageNo.toString() } }]; const jiraPayload = { foo: "bar", - pullRequests: [{ id: "pid" + pageCursor.pageNo }], - builds: [{ id: "bid" + pageCursor.pageNo }] + pullRequests: [{ id: "pid" + pageCursor.pageNo.toString() }], + builds: [{ id: "bid" + pageCursor.pageNo.toString() }] }; return Promise.resolve({ edges, jiraPayload }); }); @@ -65,9 +65,9 @@ describe("fetchNextPagesInParallel", () => { } const edges = [{ cursor: pageCursor.serialise(), - node: { id: "id" + pageCursor.pageNo } + node: { id: "id" + pageCursor.pageNo.toString() } }]; - const jiraPayload = { pullRequests: [{ id: "pid" + pageCursor.pageNo }] }; + const jiraPayload = { pullRequests: [{ id: "pid" + pageCursor.pageNo.toString() }] }; return Promise.resolve({ edges, jiraPayload }); }); const fetchedData = await fetchNextPagesInParallel(2, new PageSizeAwareCounterCursor("1"), singlePageFetchFactory); @@ -86,9 +86,9 @@ describe("fetchNextPagesInParallel", () => { } const edges = [{ cursor: pageCursor.serialise(), - node: { id: "id" + pageCursor.pageNo } + node: { id: "id" + pageCursor.pageNo.toString() } }]; - const jiraPayload = { pullRequests: [{ id: "pid" + pageCursor.pageNo }] }; + const jiraPayload = { pullRequests: [{ id: "pid" + pageCursor.pageNo.toString() }] }; return Promise.resolve({ edges, jiraPayload }); }); await expect(fetchNextPagesInParallel(2, new PageSizeAwareCounterCursor("1"), singlePageFetchFactory)).rejects.toThrowError("foo"); diff --git a/src/sync/scheduler.test.ts b/src/sync/scheduler.test.ts index cfdd473030..85487cb4a4 100644 --- a/src/sync/scheduler.test.ts +++ b/src/sync/scheduler.test.ts @@ -22,8 +22,8 @@ describe("scheduler", () => { delete newRepoSyncState["commitStatus"]; delete newRepoSyncState["branchStatus"]; newRepoSyncState["repoId"] = repoSyncState.repoId + newRepoStateNo; - newRepoSyncState["repoName"] = repoSyncState.repoName + newRepoStateNo; - newRepoSyncState["repoFullName"] = repoSyncState.repoFullName + newRepoStateNo; + newRepoSyncState["repoName"] = repoSyncState.repoName + newRepoStateNo.toString(); + newRepoSyncState["repoFullName"] = repoSyncState.repoFullName + newRepoStateNo.toString(); newRepoSyncStatesData.push(newRepoSyncState); } await RepoSyncState.bulkCreate(newRepoSyncStatesData); @@ -158,9 +158,9 @@ describe("scheduler", () => { const tasks = await getNextTasks(subscription, [], getLogger("test")); const repoIdsAndTaskType = new Set(); tasks.otherTasks.forEach(task => { - repoIdsAndTaskType.add("" + task.repositoryId + task.task); + repoIdsAndTaskType.add("" + task.repositoryId.toString() + task.task); }); - repoIdsAndTaskType.add("" + tasks.mainTask!.repositoryId + tasks.mainTask!.task); + repoIdsAndTaskType.add("" + tasks.mainTask!.repositoryId.toString() + tasks.mainTask!.task); expect(tasks.otherTasks.length + 1).toEqual(repoIdsAndTaskType.size); }); @@ -172,7 +172,7 @@ describe("scheduler", () => { for (let i = 0; i < 50; i++) { const tasks = await getNextTasks(subscription, [], getLogger("test")); tasks.otherTasks.forEach(task => { - otherTasksAndTaskTypes.add("" + task.repositoryId); + otherTasksAndTaskTypes.add("" + task.repositoryId.toString()); }); } // The pool size should be 100: diff --git a/src/sync/transforms/branch.ts b/src/sync/transforms/branch.ts index f43ebe0634..e6e9fae621 100644 --- a/src/sync/transforms/branch.ts +++ b/src/sync/transforms/branch.ts @@ -3,6 +3,8 @@ import { getJiraAuthor, jiraIssueKeyParser, limitCommitMessage } from "utils/jir import { isEmpty, union } from "lodash"; import { generateCreatePullRequestUrl } from "../../transforms/util/pull-request-link-generator"; import { transformRepositoryDevInfoBulk } from "~/src/transforms/transform-repository"; +import { Repository } from "models/subscription"; +import { Branch } from "~/src/github/client/github-client.types"; // TODO: better typing in file /** @@ -14,7 +16,7 @@ import { transformRepositoryDevInfoBulk } from "~/src/transforms/transform-repos * - Title of the last associated Pull Request * - Message from the last commit in that branch */ -const mapBranch = (branch, repository, alwaysSend: boolean) => { +const mapBranch = (branch: Branch, repository: Repository, alwaysSend: boolean) => { const branchKeys = jiraIssueKeyParser(branch.name); const pullRequestKeys = jiraIssueKeyParser( branch.associatedPullRequests.nodes.length ? branch.associatedPullRequests.nodes[0].title : "" @@ -83,7 +85,7 @@ const mapCommit = (commit, alwaysSend: boolean) => { * @param payload * @param gitHubBaseUrl - can be undefined for Cloud */ -export const transformBranches = (payload: { branches: any, repository: any }, gitHubBaseUrl: string | undefined, alwaysSendBranches: boolean, alwaysSendCommits: boolean) => { +export const transformBranches = (payload: { branches: any, repository: Repository }, gitHubBaseUrl: string | undefined, alwaysSendBranches: boolean, alwaysSendCommits: boolean) => { // TODO: use reduce instead of map/filter const branches = payload.branches .map((branch) => mapBranch(branch, payload.repository, alwaysSendBranches)) diff --git a/src/transforms/push.ts b/src/transforms/push.ts index d01a390aae..7234b75ba9 100644 --- a/src/transforms/push.ts +++ b/src/transforms/push.ts @@ -32,7 +32,7 @@ const mapFile = ( unchanged: JiraCommitFileChangeTypeEnum.UNKNOWN }; - const fallbackUrl = `https://github.com/${repoOwner}/${repoName}/blob/${commitHash}/${githubFile.filename}`; + const fallbackUrl = `https://github.com/${repoOwner ?? "undefined"}/${repoName}/blob/${commitHash}/${githubFile.filename}`; if (isEmpty(githubFile.filename)) { return undefined; diff --git a/src/transforms/transform-code-scanning-alert.ts b/src/transforms/transform-code-scanning-alert.ts index dbfe451aa2..2b5eb28e2c 100644 --- a/src/transforms/transform-code-scanning-alert.ts +++ b/src/transforms/transform-code-scanning-alert.ts @@ -91,9 +91,9 @@ export const transformCodeScanningAlert = async (context: WebhookContext, github return { remoteLinks: [{ schemaVersion: "1.0", - id: `${transformRepositoryId(repository.id, gitHubInstallationClient.baseUrl)}-${alert.number}`, + id: `${transformRepositoryId(repository.id, gitHubInstallationClient.baseUrl)}-${alert.number as number}`, updateSequenceNumber: Date.now(), - displayName: `Alert #${alert.number}`, + displayName: `Alert #${alert.number as number}`, description: alert.rule.description.substring(0, MAX_STRING_LENGTH) || undefined, url: alert.html_url, type: "security", @@ -124,15 +124,15 @@ export const transformCodeScanningAlertToJiraSecurity = async (context: WebhookC }; const gitHubInstallationClient = await createInstallationClient(githubInstallationId, jiraHost, metrics, context.log, context.gitHubAppConfig?.gitHubAppId); - const handleUnmappedState = (state) => context.log.info(`Received unmapped state from code_scanning_alert webhook: ${state}`); - const handleUnmappedSeverity = (severity) => context.log.info(`Received unmapped severity from code_scanning_alert webhook: ${severity}`); + const handleUnmappedState = (state: string) => context.log.info(`Received unmapped state from code_scanning_alert webhook: ${state}`); + const handleUnmappedSeverity = (severity: string | null) => context.log.info(`Received unmapped severity from code_scanning_alert webhook: ${severity ?? "Missing Severity"}`); const identifiers = transformRuleTagsToIdentifiers(alert.rule.tags); return { vulnerabilities: [{ schemaVersion: "1.0", - id: `c-${transformRepositoryId(repository.id, gitHubInstallationClient.baseUrl)}-${alert.number}`, + id: `c-${transformRepositoryId(repository.id, gitHubInstallationClient.baseUrl)}-${alert.number as number}`, updateSequenceNumber: Date.now(), containerId: transformRepositoryId(repository.id, gitHubInstallationClient.baseUrl), displayName: alert.rule.name, diff --git a/src/transforms/transform-dependabot-alert.ts b/src/transforms/transform-dependabot-alert.ts index 71f6505223..00cd9859ab 100644 --- a/src/transforms/transform-dependabot-alert.ts +++ b/src/transforms/transform-dependabot-alert.ts @@ -34,8 +34,8 @@ export const transformDependabotAlert = async (context: WebhookContext context.log.info(`Received unmapped state from dependabot_alert webhook: ${state}`); - const handleUnmappedSeverity = (severity) => context.log.info(`Received unmapped severity from dependabot_alert webhook: ${severity}`); + const handleUnmappedState = (state: string) => context.log.info(`Received unmapped state from dependabot_alert webhook: ${state}`); + const handleUnmappedSeverity = (severity: string | null) => context.log.info(`Received unmapped severity from dependabot_alert webhook: ${severity ?? "Missing Serverity"}`); return { vulnerabilities: [{ diff --git a/src/transforms/transform-deployment.test.ts b/src/transforms/transform-deployment.test.ts index f21842cf5d..7cff9ee74b 100644 --- a/src/transforms/transform-deployment.test.ts +++ b/src/transforms/transform-deployment.test.ts @@ -288,7 +288,7 @@ describe("transform GitHub webhook payload to Jira payload", () => { ]); // Compare commits - githubNock.get(`/repos/${owner.login}/${repoName}/compare/6e87a40179eb7ecf5094b9c8d690db727472d5bc...${deploymentPayload.deployment.sha}`) + githubNock.get(`/repos/${owner.login}/${repoName}/compare/6e87a40179eb7ecf5094b9c8d690db727472d5bc...${deploymentPayload.deployment.sha as string}`) .reply(200, { commits: [] }); mockGetRepoConfigNoServices(); @@ -697,7 +697,7 @@ describe("transform GitHub webhook payload to Jira payload", () => { const jiraPayload = await transformDeployment(gitHubClient, deployment_status.payload as any, jiraHost, "webhook", getLogger("deploymentLogger"), undefined); // make expected issue id array - const expectedIssueIds = [...Array(500).keys()].map(number => "ABC-" + (number + 1)); + const expectedIssueIds = [...Array(500).keys()].map(number => "ABC-" + (number + 1).toString()); expect(jiraPayload).toMatchObject(buildJiraPayload("testing", [ { @@ -733,7 +733,7 @@ describe("transform GitHub webhook payload to Jira payload", () => { expect(jiraPayload).toMatchObject(buildJiraPayload("testing", [ { associationType: "issueIdOrKeys", - values: [...Array(499).keys()].map(number => "ABC-" + (number + 1)) + values: [...Array(499).keys()].map(number => "ABC-" + (number + 1).toString()) }, { associationType: "serviceIdOrKeys", @@ -779,7 +779,7 @@ describe("transform GitHub webhook payload to Jira payload", () => { expect(jiraPayload).toMatchObject(buildJiraPayload("testing", [ { associationType: "issueIdOrKeys", - values: [...Array(497).keys()].map(number => "ABC-" + (number + 1)) + values: [...Array(497).keys()].map(number => "ABC-" + (number + 1).toString()) }, { associationType: "serviceIdOrKeys", diff --git a/src/transforms/transform-pull-request.ts b/src/transforms/transform-pull-request.ts index 66eac1642d..9f7b5fa241 100644 --- a/src/transforms/transform-pull-request.ts +++ b/src/transforms/transform-pull-request.ts @@ -96,7 +96,7 @@ export const extractIssueKeysFromPrRest = async (pullRequest: Octokit.PullsListR export const extractIssueKeysFromPr = (pullRequest: pullRequestNode) => { const { title, headRef, body } = pullRequest; - return jiraIssueKeyParser(`${title}\n${headRef?.name}\n${body}`); + return jiraIssueKeyParser(`${title}\n${headRef?.name ?? ""}\n${body}`); }; export const transformPullRequestRest = async ( diff --git a/src/transforms/transform-repository-id.ts b/src/transforms/transform-repository-id.ts index 82d1fd01f4..7c5d30ccb5 100644 --- a/src/transforms/transform-repository-id.ts +++ b/src/transforms/transform-repository-id.ts @@ -31,7 +31,7 @@ const calculatePrefix = (url: string) => { */ export const transformRepositoryId = (repositoryId: number, gitHubBaseUrl?: string): TransformedRepositoryId => { if (!gitHubBaseUrl || calculatePrefix(gitHubBaseUrl) === calculatePrefix(GITHUB_CLOUD_BASEURL)) { - return ("" + repositoryId) as TransformedRepositoryId; + return (repositoryId?.toString() || "undefined") as TransformedRepositoryId; } return `${calculatePrefix(gitHubBaseUrl)}-${repositoryId}` as TransformedRepositoryId; diff --git a/src/transforms/transform-secret-scanning-alert.ts b/src/transforms/transform-secret-scanning-alert.ts index 708ecc7e32..e5ddbd6b68 100644 --- a/src/transforms/transform-secret-scanning-alert.ts +++ b/src/transforms/transform-secret-scanning-alert.ts @@ -44,7 +44,7 @@ export const transformSecretScanningAlert = async ( // To Jira: Status can be one of: : open, closed export const transformGitHubStateToJiraStatus = (state: string | undefined, logger: Logger): JiraVulnerabilityStatusEnum => { if (!state) { - logger.info(`Received unmapped state from secret_scanning_alert webhook: ${state}`); + logger.info(`Received unmapped state from secret_scanning_alert webhook: ${state ?? "Missing State"}`); return JiraVulnerabilityStatusEnum.UNKNOWN; } switch (state) { diff --git a/src/transforms/transform-workflow.ts b/src/transforms/transform-workflow.ts index 1ca3251692..cbdfb674c1 100644 --- a/src/transforms/transform-workflow.ts +++ b/src/transforms/transform-workflow.ts @@ -83,7 +83,7 @@ export const transformWorkflow = async ( logger ) : ""; - const issueKeys = jiraIssueKeyParser(`${head_branch}\n${payload.workflow_run.head_commit?.message}\n${commitMessages}`); + const issueKeys = jiraIssueKeyParser(`${head_branch}\n${payload.workflow_run.head_commit?.message ?? ""}\n${commitMessages}`); if (!issueKeys.length && !alwaysSend) { return undefined; } diff --git a/src/util/create-url-with-query-string.ts b/src/util/create-url-with-query-string.ts index 6ef3e879eb..b849fd46f0 100644 --- a/src/util/create-url-with-query-string.ts +++ b/src/util/create-url-with-query-string.ts @@ -13,7 +13,8 @@ export const createUrlWithQueryString = (req: Request, URL: string): string => { const queryStrings = keys.reduce((_, current, index, array) => { if (req.query[current]) { queryString += index === 0 ? "?" : ""; - queryString += current + "=" + req.query[current]; + queryString += current + "="; + queryString += req.query[current]; queryString += index !== array.length - 1 ? "&" : ""; } return queryString; diff --git a/src/util/curl/curl-utils.test.ts b/src/util/curl/curl-utils.test.ts index f2dab93496..769dfc26e6 100644 --- a/src/util/curl/curl-utils.test.ts +++ b/src/util/curl/curl-utils.test.ts @@ -35,7 +35,7 @@ describe("curl-utils", () => { describe("logCurlOutput", () => { it("should not explode with empty output", () => { - logCurlOutputInChunks({ body: "", meta: "" }, getLogger("test")); + expect(() => logCurlOutputInChunks({ body: "", meta: "" }, getLogger("test"))).not.toThrowError(); }); it("should not explode with non-empty output", async () => { @@ -44,7 +44,7 @@ describe("curl-utils", () => { method: "GET", authorization: "secrets" }); - logCurlOutputInChunks(result, getLogger("test")); + expect(() => logCurlOutputInChunks(result, getLogger("test"))).not.toThrowError(); }); }); }); diff --git a/src/util/error-string-from-unknown.ts b/src/util/error-string-from-unknown.ts new file mode 100644 index 0000000000..0dbb2e9185 --- /dev/null +++ b/src/util/error-string-from-unknown.ts @@ -0,0 +1,3 @@ +export const errorStringFromUnknown = (e : unknown) : string => { + return e instanceof Error ? e.toString() : "unkown"; +}; diff --git a/src/util/handlebars/handlebar-helpers.ts b/src/util/handlebars/handlebar-helpers.ts index f159d0347a..ecd849abc7 100644 --- a/src/util/handlebars/handlebar-helpers.ts +++ b/src/util/handlebars/handlebar-helpers.ts @@ -21,7 +21,7 @@ export const registerHandlebarsHelpers = () => { hbs.registerHelper( "ifAllReposSynced", - (numberOfSyncedRepos, totalNumberOfRepos) => + (numberOfSyncedRepos: number, totalNumberOfRepos: number): any => numberOfSyncedRepos === totalNumberOfRepos ? totalNumberOfRepos : `${numberOfSyncedRepos} / ${totalNumberOfRepos}` @@ -33,7 +33,7 @@ export const registerHandlebarsHelpers = () => { hbs.registerHelper("isNotConnected", (syncStatus) => syncStatus == null); - hbs.registerHelper("setSubscriptionUrl", (uuid, installationId) => uuid + hbs.registerHelper("setSubscriptionUrl", (uuid: string, installationId: number) => uuid ? `/github/${uuid}/subscriptions/${installationId}` : `/github/subscriptions/${installationId}` ); diff --git a/src/util/jira-utils.test.ts b/src/util/jira-utils.test.ts index 9a4fed2e5f..dc363a76ed 100644 --- a/src/util/jira-utils.test.ts +++ b/src/util/jira-utils.test.ts @@ -115,7 +115,7 @@ describe("Jira Utils", () => { ["JIRA-123abcd"], ["JIRA-123abcd JIRA-456 abcd", "JIRA-456"] ])("matching with whole word", (full, ...issueKeys) => { - it(`should match "${full}" to "${issueKeys}"`, () => { + it(`should match "${full}" to "${issueKeys.toString()}"`, () => { expect(jiraIssueKeyParser(full)).toEqual(issueKeys ? issueKeys : []); }); }); diff --git a/src/util/logger-utils.ts b/src/util/logger-utils.ts index a157f2dfd0..34114a75f8 100644 --- a/src/util/logger-utils.ts +++ b/src/util/logger-utils.ts @@ -40,7 +40,7 @@ class RawLogStream extends Writable { return next(); } - const chunk = safeJsonStringify(record) + "\n"; + const chunk = `${safeJsonStringify(record)}\n`; this.writeStream.write(chunk, encoding); next(); } diff --git a/src/util/workers-health-monitor.ts b/src/util/workers-health-monitor.ts index 62484997be..6f0f55be3d 100644 --- a/src/util/workers-health-monitor.ts +++ b/src/util/workers-health-monitor.ts @@ -9,7 +9,7 @@ export const startMonitorOnWorker = (parentLogger: Logger, iAmAliveInervalMsec: const logger = parentLogger.child({ isWorker: true }); logger.info({ iAmAliveInervalMsec }, "worker config"); - process.on("message", (msg) => { + process.on("message", (msg: string) => { logger.info(`worker received a message: ${msg}`); if (msg === CONF_SHUTDOWN_MSG) { logger.warn("shutdown received, stop healthcheck"); @@ -32,7 +32,7 @@ export const startMonitorOnWorker = (parentLogger: Logger, iAmAliveInervalMsec: const logRunningProcesses = (logger: Logger) => { exec("ps aux", (err, stdout) => { if (err) { - logger.error({ err }, `exec error: ${err}`); + logger.error({ err }, `exec error: ${err.toString()}`); return; } @@ -64,7 +64,7 @@ export const startMonitorOnMaster = (parentLogger: Logger, config: { logger.info(`registering a new worker with pid=${workerPid}`); registeredWorkers[workerPid] = true; worker.on("message", () => { - logInfoSampled(logger, "workerIsAlive:" + workerPid, `received message from worker ${workerPid}, marking as live`, 100); + logInfoSampled(logger, `workerIsAlive:${workerPid}`, `received message from worker ${workerPid}, marking as live`, 100); liveWorkers[workerPid] = Date.now(); }); worker.on("exit", (code, signal) => { @@ -87,7 +87,7 @@ export const startMonitorOnMaster = (parentLogger: Logger, config: { if (!workersReadyAt) { if (Object.keys(registeredWorkers).length > config.numberOfWorkersThreshold) { workersReadyAt = new Date(Date.now() + config.workerStartupTimeMsecs); - logger.info(`consider workers as ready after ${workersReadyAt}`); + logger.info(`consider workers as ready after ${workersReadyAt?.toString()}`); } else { logger.info("no enough workers"); } diff --git a/test/e2e/utils/jira.ts b/test/e2e/utils/jira.ts index 84ef3d1fff..e5e33764f3 100644 --- a/test/e2e/utils/jira.ts +++ b/test/e2e/utils/jira.ts @@ -105,7 +105,7 @@ export const jiraCreateIssue = async (page: Page, projectId: string = testData.p // V3 implementation // await page.click("[data-testid='navigation-apps-sidebar-next-gen.ui.menu.software-backlog-link']"); // const taskInput = page.locator("[data-test-id='platform-inline-card-create.ui.form.summary.styled-text-area']"); - await taskInput.fill("Task " + Date.now()); + await taskInput.fill("Task " + Date.now().toString()); await taskInput.press("Enter"); const url = await page.locator("[data-test-id='platform-board-kit.ui.column.draggable-column.styled-wrapper']:first-child [data-test-id='platform-board-kit.ui.card.card'][draggable]").last().getAttribute("id"); return url?.replace("card-", "") || ""; diff --git a/test/setup/matchers/to-be-called-with-delay.ts b/test/setup/matchers/to-be-called-with-delay.ts index 1b703821e5..b9060ba0cb 100644 --- a/test/setup/matchers/to-be-called-with-delay.ts +++ b/test/setup/matchers/to-be-called-with-delay.ts @@ -8,7 +8,7 @@ declare namespace jest { expect.extend({ toBeCalledWithDelaySec: async (received: jest.Mock, expectedDelaySec: number) => { - const actual = received.mock?.calls[0][0].DelaySeconds; + const actual = received.mock?.calls[0][0].DelaySeconds as number; const pass = actual == expectedDelaySec; const message = () => `Expected parameter to have DelaySeconds = ${expectedDelaySec} ${pass ? "" : `but was ${actual}`}`; diff --git a/test/setup/matchers/to-promise.ts b/test/setup/matchers/to-promise.ts index 42694158ec..82548bf431 100644 --- a/test/setup/matchers/to-promise.ts +++ b/test/setup/matchers/to-promise.ts @@ -25,7 +25,7 @@ expect.extend({ } return { pass: false, - message: () => `Expected promise to resolve, however it rejected with error: \n${error.stack}\n` + message: () => `Expected promise to resolve, however it rejected with error: \n${error.stack ?? "Missing Stack"}\n` }; }, toReject: async (promise: Promise) => { diff --git a/test/setup/setup.ts b/test/setup/setup.ts index 7374757a13..7ffbdbf6ab 100644 --- a/test/setup/setup.ts +++ b/test/setup/setup.ts @@ -131,7 +131,7 @@ beforeAll(async () => { }); beforeEach(() => { - const instance = envVars.APP_KEY.split(".").pop(); + const instance = envVars.APP_KEY.split(".").pop()!; global.jiraHost = process.env.ATLASSIAN_URL || `https://${instance}.atlassian.net`; global.jiraStaginHost = process.env.ATLASSIAN_URL?.replace(".atlassian.net", ".jira-dev.com") || `https://${instance}.jira-dev.com`; global.jiraNock = nock(global.jiraHost); diff --git a/test/snapshots/routes/api/api-router.test.ts.snap b/test/snapshots/routes/api/api-router.test.ts.snap index 4dcd234053..4729a3adbb 100644 --- a/test/snapshots/routes/api/api-router.test.ts.snap +++ b/test/snapshots/routes/api/api-router.test.ts.snap @@ -33,7 +33,7 @@ Object { "failedConnections": Array [ Object { "deleted": false, - "error": "Error executing Axios Request: Request failed with status code 500. More details in logs", + "error": "Error: Error executing Axios Request: Request failed with status code 500. More details in logs", "id": 1234, }, ], diff --git a/test/snapshots/snapshot-resolver.ts b/test/snapshots/snapshot-resolver.ts index 88e311a535..840ff12224 100644 --- a/test/snapshots/snapshot-resolver.ts +++ b/test/snapshots/snapshot-resolver.ts @@ -9,7 +9,7 @@ module.exports = { * @param testPath Path of the test file being tested * @param snapshotExtension The extension for snapshots (.snap usually) */ - resolveSnapshotPath:(testPath, snapshotExtension) => + resolveSnapshotPath:(testPath: string, snapshotExtension: string) => path.join(snapshotDirPath, testPath.replace(srcPath, "") + snapshotExtension), /** diff --git a/test/utils/database-state-creator.ts b/test/utils/database-state-creator.ts index 5076a463bd..3bc146e1ed 100644 --- a/test/utils/database-state-creator.ts +++ b/test/utils/database-state-creator.ts @@ -120,7 +120,7 @@ export class DatabaseStateCreator { uuid: v4(), appId: 12321, gitHubBaseUrl: gheUrl, - gitHubClientId: "client-id" + Math.random(), + gitHubClientId: "client-id" + Math.random().toString(), gitHubClientSecret: "client-secret", webhookSecret: "webhook-secret", privateKey: fs.readFileSync(path.resolve(__dirname, "../../test/setup/test-key.pem"), { encoding: "utf8" }), diff --git a/yarn.lock b/yarn.lock index 797931b3ae..d56fa9ecc8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1235,6 +1235,11 @@ dependencies: "@types/node" "*" +"@types/safe-json-stringify@^1.1.2": + version "1.1.2" + resolved "https://packages.atlassian.com/api/npm/npm-remote/@types/safe-json-stringify/-/safe-json-stringify-1.1.2.tgz#913796617042de2259f62ce82843c239258ca287" + integrity sha512-Hj/LZMBXFH3Qj9sNmNu6syBpkZqBaM00HgP7naf9CnZhB3kdxmrenWUD2cY6vvTWjuBM3NPOLknPKDUOQuTWXA== + "@types/semver@^7.3.12": version "7.5.1" resolved "https://packages.atlassian.com/api/npm/npm-remote/@types/semver/-/semver-7.5.1.tgz#0480eeb7221eb9bc398ad7432c9d7e14b1a5a367"