Skip to content
Permalink

Comparing changes

This is a direct comparison between two commits made in this repository or its related repositories. View the default comparison for this range or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: atlassian/github-for-jira
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: e626c76b6e32cb07c23fb58d78a3de70dfbeb26d
Choose a base ref
..
head repository: atlassian/github-for-jira
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 70564652bcf334dc628c8ea5086a0ff1ca138773
Choose a head ref
Showing with 1,377 additions and 1,121 deletions.
  1. +1 −1 .nvmrc
  2. +1 −1 Dockerfile
  3. +2 −2 Dockerfile.prod
  4. +9 −7 package.json
  5. +1 −1 spa/jest.config.json
  6. +1 −1 spa/package.json
  7. +1 −0 spa/setup.ts
  8. +10 −0 spa/src/components/Error/KnownErrors/index.tsx
  9. +10 −18 spa/yarn.lock
  10. +1 −1 src/config/feature-flags.test.ts
  11. +0 −1 src/config/feature-flags.ts
  12. +1 −1 src/github/client/token-cache.test.ts
  13. +1 −1 src/middleware/github-webhook-middleware.test.ts
  14. +4 −16 src/middleware/jira-symmetric-jwt-middleware.test.ts
  15. +4 −11 src/middleware/jira-symmetric-jwt-middleware.ts
  16. +1 −1 src/models/reposyncstate.test.ts
  17. +1 −1 src/routes/api/api-replay-failed-entities-from-data-depot.test.ts
  18. +1 −1 src/routes/api/api-resync-failed-tasks.test.ts
  19. +1 −1 src/routes/github/branch/github-branch-get.test.ts
  20. +1 −1 src/routes/github/create-branch/github-branches-get.test.ts
  21. +1 −1 src/routes/github/create-branch/github-create-branch-post.test.ts
  22. +2 −26 src/routes/jira/atlassian-connect/jira-atlassian-connect-get.test.ts
  23. +16 −26 src/routes/jira/atlassian-connect/jira-atlassian-connect-get.ts
  24. +1 −1 src/routes/jira/events/jira-events-install-post.test.ts
  25. +1 −1 src/routes/jira/jira-delete.test.ts
  26. +0 −8 src/routes/jira/workspaces/jira-workspaces-get.test.ts
  27. +0 −6 src/routes/jira/workspaces/repositories/jira-workspaces-repositories-associate.test.ts
  28. +0 −8 src/routes/jira/workspaces/repositories/jira-workspaces-repositories-get.test.ts
  29. +3 −3 src/transforms/transform-code-scanning-alert.test.ts
  30. +1 −1 src/util/jira-utils.test.ts
  31. +14 −14 test/snapshots/jira/client/jira-client.test.ts.snap
  32. +15 −15 test/snapshots/routes/api/api-router.test.ts.snap
  33. +4 −4 test/snapshots/routes/github/subscription/github-subscription-delete.test.ts.snap
  34. +87 −78 test/snapshots/routes/jira/atlassian-connect/jira-atlassian-connect-get.test.ts.snap
  35. +90 −81 test/snapshots/routes/maintenance/maintenance-router.test.ts.snap
  36. +1,090 −781 yarn.lock
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
14.21.1
18.18.1
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM node:14.21-alpine3.16 as build
FROM node:18-alpine3.18 as build

# adding python for node-gyp
RUN apk add g++ make python3
4 changes: 2 additions & 2 deletions Dockerfile.prod
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM node:14.21-alpine3.16 as build
FROM node:18-alpine3.18 as build

# adding python for node-gyp
RUN apk add g++ make python3
@@ -28,7 +28,7 @@ RUN yarn run build:release
# https://stackoverflow.com/questions/57108751/docker-build-failed-when-copying-in-multi-step-build
RUN chown root:root -R /app

FROM node:14.21-alpine3.16
FROM node:18-alpine3.18

# adding to solve vuln
RUN apk add --update --upgrade busybox
16 changes: 9 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@
"description": "GitHub integration for Atlassian Jira",
"repository": "https://github.com/atlassian/github-for-jira.git",
"engines": {
"node": ">= 14.21 <15",
"node": ">= 18.18.1",
"yarn": "^1.22.0"
},
"main": "src/main",
@@ -28,7 +28,7 @@
"lint:ts": "eslint . --ext .ts,.tsx",
"lint:yaml": "yamllint github-for-jira.sd.yml",
"pretest": "NODE_ENV=test run-p clean setup db:test",
"test": "yarn spa:test && jest --runInBand --forceExit --coverage",
"test": "yarn spa:test && jest --forceExit --coverage --runInBand --logHeapUsage --workerIdleMemoryLimit='2GB'",
"test:watch": "jest --runInBand --watchAll --coverage=false",
"db": "run-s db:create db:migrate",
"db:create": "run-p db:create:dev db:create:test",
@@ -95,6 +95,7 @@
"helmet": "^3.21.2",
"hot-shots": "^8.3.2",
"http-proxy": "^1.18.1",
"http-proxy-agent": "^7.0.0",
"https-proxy-agent": "5.0.0",
"ioredis": "^4.16.3",
"is-base64": "^1.1.0",
@@ -157,13 +158,14 @@
"eslint-import-resolver-typescript": "^2.5.0",
"eslint-plugin-import": "^2.25.4",
"eslint-plugin-jest": "^27.4.0",
"eslint-plugin-jsdoc": "^37.9.3",
"eslint-plugin-jsdoc": "^46.8.2",
"eslint-plugin-no-only-tests": "^2.6.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^6.0.0",
"husky": "^6.0.0",
"jest": "^27.5.1",
"jest-diff": "^27.5.1",
"jest": "^29.7.0",
"jest-diff": "^29.7",
"jest-environment-jsdom": "^29.7.0",
"jest-when": "^3.5.1",
"keygrip": "^1.0.2",
"nock": "^13.2.4",
@@ -175,7 +177,7 @@
"smee-client": "^1.2.2",
"sqlite3": "^5.1.5",
"supertest": "^6.2.2",
"ts-jest": "~27.1.3",
"ts-jest": "^29.1.1",
"ts-node": "^10.5.0",
"ts-node-dev": "^2.0.0",
"yaml-lint": "^1.2.4"
@@ -184,7 +186,7 @@
"@atlassian/sqs-queue-dlq-service": "^2.1.1"
},
"volta": {
"node": "14.21.1",
"node": "18.18.1",
"yarn": "1.22.18"
}
}
2 changes: 1 addition & 1 deletion spa/jest.config.json
Original file line number Diff line number Diff line change
@@ -4,6 +4,6 @@
"^.+\\.tsx?$": "ts-jest"
},
"setupFilesAfterEnv": [
"@testing-library/jest-dom/extend-expect"
"./setup.ts"
]
}
2 changes: 1 addition & 1 deletion spa/package.json
Original file line number Diff line number Diff line change
@@ -48,7 +48,7 @@
"simplebar-react": "^3.2.4"
},
"devDependencies": {
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/jest-dom": "^6.1.4",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^14.4.3",
"@types/jest": "^29.5.2",
1 change: 1 addition & 0 deletions spa/setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import "@testing-library/jest-dom";
10 changes: 10 additions & 0 deletions spa/src/components/Error/KnownErrors/index.tsx
Original file line number Diff line number Diff line change
@@ -17,6 +17,7 @@ import Modal, {
import TextArea from "@atlaskit/textarea";
import Spinner from "@atlaskit/spinner";
import Button from "@atlaskit/button";
import WarningIcon from "@atlaskit/icon/glyph/warning";

const olStyle = css`
padding-left: 1.2em;
@@ -35,6 +36,11 @@ const linkStyle = css`
const textAreaStyle = css`
margin-top: 20px;
`;
const expireTextWrapperStyle = css`
display: flex;
align-items: center;
margin-top: ${token("space.100")};
`;

/************************************************************************
* UI view for the 3 known errors
@@ -137,6 +143,10 @@ export const ErrorForNonAdmins = ({ orgName, adminOrgsUrl, onPopupBlocked, defer
Find an organization owner
</a>
</div>
<div css={expireTextWrapperStyle}>
<WarningIcon label="warning" primaryColor={token("color.background.warning.bold")} />
<b>Note that the following link will expire after 2 days.</b>
</div>
<TextArea
onCopy={() => {
analyticsClient.sendUIEvent({ actionSubject: "copiedDeferredInstallationUrl", action: "clicked"}, { type: "cloud" });
28 changes: 10 additions & 18 deletions spa/yarn.lock
Original file line number Diff line number Diff line change
@@ -7,10 +7,10 @@
resolved "https://packages.atlassian.com/api/npm/npm-remote/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf"
integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==

"@adobe/css-tools@^4.0.1":
version "4.2.0"
resolved "https://packages.atlassian.com/api/npm/npm-remote/@adobe/css-tools/-/css-tools-4.2.0.tgz#e1a84fca468f4b337816fcb7f0964beb620ba855"
integrity sha512-E09FiIft46CmH5Qnjb0wsW54/YQd69LsxeKUOWawmws1XWvyFGURnAChH0mlr7YPFR1ofwvUQfcL0J3lMxXqPA==
"@adobe/css-tools@^4.3.1":
version "4.3.1"
resolved "https://packages.atlassian.com/api/npm/npm-remote/@adobe/css-tools/-/css-tools-4.3.1.tgz#abfccb8ca78075a2b6187345c26243c1a0842f28"
integrity sha512-/62yikz7NLScCGAAST5SHdnjaDJQBDq0M2muyRTpf2VQhw6StBg2ALiu73zSJQ4fMVLA+0uBhBHAle7Wg+2kSg==

"@alloc/quick-lru@^5.2.0":
version "5.2.0"
@@ -2930,14 +2930,13 @@
lz-string "^1.5.0"
pretty-format "^27.0.2"

"@testing-library/jest-dom@^5.16.5":
version "5.16.5"
resolved "https://packages.atlassian.com/api/npm/npm-remote/@testing-library/jest-dom/-/jest-dom-5.16.5.tgz#3912846af19a29b2dbf32a6ae9c31ef52580074e"
integrity sha512-N5ixQ2qKpi5OLYfwQmUb/5mSV9LneAcaUfp32pn4yCnpb8r/Yz0pXFPck21dIicKmi+ta5WRAknkZCfA8refMA==
"@testing-library/jest-dom@^6.1.4":
version "6.1.4"
resolved "https://packages.atlassian.com/api/npm/npm-remote/@testing-library/jest-dom/-/jest-dom-6.1.4.tgz#cf0835c33bc5ef00befb9e672b1e3e6a710e30e3"
integrity sha512-wpoYrCYwSZ5/AxcrjLxJmCU6I5QAJXslEeSiMQqaWmP2Kzpd1LvF/qxmAIW2qposULGWq2gw30GgVNFLSc2Jnw==
dependencies:
"@adobe/css-tools" "^4.0.1"
"@adobe/css-tools" "^4.3.1"
"@babel/runtime" "^7.9.2"
"@types/testing-library__jest-dom" "^5.9.1"
aria-query "^5.0.0"
chalk "^3.0.0"
css.escape "^1.5.1"
@@ -3144,7 +3143,7 @@
dependencies:
"@types/istanbul-lib-report" "*"

"@types/jest@*", "@types/jest@^29.5.2":
"@types/jest@^29.5.2":
version "29.5.2"
resolved "https://packages.atlassian.com/api/npm/npm-remote/@types/jest/-/jest-29.5.2.tgz#86b4afc86e3a8f3005b297ed8a72494f89e6395b"
integrity sha512-mSoZVJF5YzGVCk+FsDxzDuH7s+SCkzrgKZzf0Z0T2WudhBUPoF6ktoTPC4R0ZoCPCV5xUvuU6ias5NvxcBcMMg==
@@ -3336,13 +3335,6 @@
resolved "https://packages.atlassian.com/api/npm/npm-remote/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c"
integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==

"@types/testing-library__jest-dom@^5.9.1":
version "5.14.6"
resolved "https://packages.atlassian.com/api/npm/npm-remote/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.6.tgz#4887f6e1af11215428ab02777873bcede98a53b0"
integrity sha512-FkHXCb+ikSoUP4Y4rOslzTdX5sqYwMxfefKh1GmZ8ce1GOkEHntSp6b5cGadmNfp5e4BMEWOMx+WSKd5/MqlDA==
dependencies:
"@types/jest" "*"

"@types/tough-cookie@*":
version "4.0.2"
resolved "https://packages.atlassian.com/api/npm/npm-remote/@types/tough-cookie/-/tough-cookie-4.0.2.tgz#6286b4c7228d58ab7866d19716f3696e03a09397"
2 changes: 1 addition & 1 deletion src/config/feature-flags.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import LaunchDarkly, { LDClient } from "launchdarkly-node-server-sdk";
import { mocked } from "ts-jest/utils";
import { mocked } from "jest-mock";

jest.mock("launchdarkly-node-server-sdk");

1 change: 0 additions & 1 deletion src/config/feature-flags.ts
Original file line number Diff line number Diff line change
@@ -27,7 +27,6 @@ export enum BooleanFlags {
EARLY_EXIT_ON_VALIDATION_FAILED = "early-exit-on-validation-failed",
ENABLE_CONNECTED_REPOS_VIEW="enable-connected-repos-view",
USE_REST_API_FOR_DISCOVERY = "use-rest-api-for-discovery-again",
ENABLE_GENERIC_CONTAINERS = "enable-generic-containers",
ENABLE_GITHUB_SECURITY_IN_JIRA = "enable-github-security-in-jira",
DELETE_MESSAGE_ON_BACKFILL_WHEN_OTHERS_WORKING_ON_IT = "delete-message-on-backfill-when-others-working-on-it",
ENABLE_5KU_BACKFILL_PAGE = "enable-5ku-experience-backfill-page",
2 changes: 1 addition & 1 deletion src/github/client/token-cache.test.ts
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@ import { AuthToken, TEN_MINUTES } from "./auth-token";
import { AppTokenHolder } from "./app-token-holder";
import { getInstallationId } from "./installation-id";
import { keyLocator } from "./key-locator";
import { mocked } from "ts-jest/utils";
import { mocked } from "jest-mock";
import { Subscription } from "~/src/models/subscription";
import { envVars } from "config/env";
import fs from "fs";
2 changes: 1 addition & 1 deletion src/middleware/github-webhook-middleware.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { mocked } from "ts-jest/utils";
import { mocked } from "jest-mock";
import { Installation } from "models/installation";
import { Subscription } from "models/subscription";
import { GithubWebhookMiddleware } from "./github-webhook-middleware";
20 changes: 4 additions & 16 deletions src/middleware/jira-symmetric-jwt-middleware.test.ts
Original file line number Diff line number Diff line change
@@ -9,12 +9,8 @@ import {
jiraSymmetricJwtMiddleware
} from "~/src/middleware/jira-symmetric-jwt-middleware";
import { Installation } from "~/src/models/installation";
import { when } from "jest-when";
import { booleanFlag, BooleanFlags } from "config/feature-flags";
import { generateSignedSessionCookieHeader } from "test/utils/cookies";


jest.mock("config/feature-flags");
const testSharedSecret = "test-secret";

const getToken = ({
@@ -224,10 +220,6 @@ describe("jiraSymmetricJwtMiddleware", () => {
host: jiraHost,
sharedSecret: testSharedSecret
});

when(booleanFlag).calledWith(
BooleanFlags.ENABLE_GENERIC_CONTAINERS, jiraHost
).mockResolvedValue(true);
});

it("should return true for search workspaces", async () => {
@@ -327,10 +319,6 @@ describe("jiraSymmetricJwtMiddleware", () => {
host: jiraHost,
sharedSecret: testSharedSecret
});

when(booleanFlag).calledWith(
BooleanFlags.ENABLE_GENERIC_CONTAINERS, jiraHost
).mockResolvedValue(true);
});

it("should return normal tokenType for search workspaces", async () => {
@@ -351,7 +339,7 @@ describe("jiraSymmetricJwtMiddleware", () => {
authorization: `JWT ${await generateJwt()}`
});

expect(await getTokenType("/jira/workspaces/search", "GET", jiraHost)).toEqual("normal");
expect(await getTokenType("/jira/workspaces/search", "GET")).toEqual("normal");
});

it("should return normal tokenType for search repositories", async () => {
@@ -376,7 +364,7 @@ describe("jiraSymmetricJwtMiddleware", () => {
)}`
});

expect(await getTokenType("/jira/workspaces/repositories/search?searchQuery=atlas", "GET", jiraHost)).toEqual("normal");
expect(await getTokenType("/jira/workspaces/repositories/search?searchQuery=atlas", "GET")).toEqual("normal");
});

it("should return normal tokenType for associate repository", async () => {
@@ -397,7 +385,7 @@ describe("jiraSymmetricJwtMiddleware", () => {
authorization: `JWT ${await generateJwt()}`
});

expect(await getTokenType("/jira/workspaces/repositories/associate", "POST", jiraHost)).toEqual("normal");
expect(await getTokenType("/jira/workspaces/repositories/associate", "POST")).toEqual("normal");
});

it("should return context tokenType for create branch", async () => {
@@ -409,7 +397,7 @@ describe("jiraSymmetricJwtMiddleware", () => {
githubToken: "random-token"
}));

expect(await getTokenType("/create-branch-options", "GET", jiraHost)).toEqual("context");
expect(await getTokenType("/create-branch-options", "GET")).toEqual("context");
});
});

15 changes: 4 additions & 11 deletions src/middleware/jira-symmetric-jwt-middleware.ts
Original file line number Diff line number Diff line change
@@ -12,7 +12,6 @@ import {
import { matchRouteWithPattern } from "~/src/util/match-route-with-pattern";
import { fetchAndSaveUserJiraAdminStatus } from "middleware/jira-admin-permission-middleware";
import { envVars } from "~/src/config/env";
import { booleanFlag, BooleanFlags } from "config/feature-flags";
import { errorStringFromUnknown } from "../util/error-string-from-unknown";
import { BaseLocals } from "../rest/routes";

@@ -97,25 +96,19 @@ const getIssuer = (token: string, logger: Logger): string | undefined => {
return unverifiedClaims.iss;
};

export const getTokenType = async (url: string, method: string, jiraHost: string): Promise<TokenType> => {
if (await booleanFlag(BooleanFlags.ENABLE_GENERIC_CONTAINERS, jiraHost)) {
return checkPathValidity(url) && method == "GET"
export const getTokenType = async (url: string, method: string): Promise<TokenType> =>
checkPathValidity(url) && method == "GET"
|| await checkGenericContainerActionUrl(`${envVars.APP_URL}${url}`)
|| checkSecurityContainerActionUrl(`${envVars.APP_URL}${url}`) ? TokenType.normal
: TokenType.context;
} else {
return checkPathValidity(url) && method == "GET"
|| checkSecurityContainerActionUrl(`${envVars.APP_URL}${url}`) ? TokenType.normal : TokenType.context;
}
};
: TokenType.context;

const verifySymmetricJwt = async (req: Request, token: string, installation: Installation) => {
const algorithm = getAlgorithm(token) as AsymmetricAlgorithm | SymmetricAlgorithm;
const secret = await installation.decrypt("encryptedSharedSecret", req.log);

try {
const claims = decodeSymmetric(token, secret, algorithm, false) as { exp?: number, qsh?: string };
const tokenType = await getTokenType(req.originalUrl, req.method, installation.jiraHost);
const tokenType = await getTokenType(req.originalUrl, req.method);

verifyJwtClaims(claims, tokenType, req);
return claims;
2 changes: 1 addition & 1 deletion src/models/reposyncstate.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { Subscription } from "./subscription";
import { RepoSyncState } from "./reposyncstate";
import { mocked } from "ts-jest/utils";
import { mocked } from "jest-mock";
import { booleanFlag } from "config/feature-flags";

jest.mock("config/feature-flags");
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ import { Installation } from "~/src/models/installation";
import { createHashWithSharedSecret } from "~/src/util/encryption";
import { RepoSyncState } from "~/src/models/reposyncstate";
import { booleanFlag } from "../../config/feature-flags";
import { mocked } from "ts-jest/utils";
import { mocked } from "jest-mock";


jest.mock("config/feature-flags");
2 changes: 1 addition & 1 deletion src/routes/api/api-resync-failed-tasks.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import express, { Application, NextFunction, Request, Response } from "express";
import { mocked } from "ts-jest/utils";
import { mocked } from "jest-mock";
import { booleanFlag } from "~/src/config/feature-flags";
import { getLogger } from "~/src/config/logger";
import { ApiRouter } from "./api-router";
2 changes: 1 addition & 1 deletion src/routes/github/branch/github-branch-get.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

import { getLogger } from "config/logger";
import { GithubBranchGet } from "routes/github/branch/github-branch-get";
import { mocked } from "ts-jest/utils";
import { mocked } from "jest-mock";
import { Subscription } from "models/subscription";

jest.mock("models/subscription");
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@
import { getLogger } from "config/logger";
import { GithubBranchesGet } from "~/src/routes/github/create-branch/github-branches-get";
import { Subscription } from "models/subscription";
import { mocked } from "ts-jest/utils";
import { mocked } from "jest-mock";

jest.mock("models/subscription");

Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@ import { Installation } from "models/installation";
import { Subscription } from "models/subscription";
import { GithubCreateBranchPost } from "./github-create-branch-post";
import { getLogger } from "config/logger";
import { mocked } from "ts-jest/utils";
import { mocked } from "jest-mock";

jest.mock("models/subscription");

Loading