diff --git a/package.json b/package.json index d2fc7d8..59f3adf 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,6 @@ "postversion": "cp package.json ./dist/package.json" }, "dependencies": { - "aws-sdk": "^2.184.0", "dotenv": "^10.0.0", "jira-client": "^7.1.0", "lodash": "^4.17.21", diff --git a/src/actions.test.ts b/src/actions.test.ts deleted file mode 100644 index c290ed9..0000000 --- a/src/actions.test.ts +++ /dev/null @@ -1,334 +0,0 @@ -import { Issue, IssueTransition, JiraClient } from './jira'; -import largeAdf from '../test/fixtures/large-adf.json'; - -process.env.JUPITERONE_ENVIRONMENT = 'jupiterone-test'; -import { - CreateIssueActionProperties, - TransitionIssueActionProperties, - createJiraIssue, - transitionJiraIssue, -} from './actions'; - -const issueDescriptionText = 'Test description'; - -/** - * The value of the `description` field for Jira API V3. - */ -const issueDescriptionADF = { - version: 1, - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: issueDescriptionText, - }, - ], - }, - ], -}; - -describe.each([[{ storedActionData: false }], [{ storedActionData: true }]])( - 'createJiraIssue', - ({ storedActionData }) => { - const projectKey = 'PROJ'; - const projectId = 123456; - - const createdIssue: Issue = { key: 'PROJ-1' } as any; - const foundIssue: Issue = { key: 'PROJ-1' } as any; - - const mockJiraClient = {} as any; - const mockS3Client = {} as any; - let actionProperties: Omit< - CreateIssueActionProperties & { storedActionData: false }, - 'storedActionData' - >; - - function getActionPropertiesToPass(): CreateIssueActionProperties { - return storedActionData - ? { storedActionData, actionDataS3Key: 'action/data/key' } - : { storedActionData, ...actionProperties }; - } - - beforeEach(() => { - mockJiraClient.apiVersion = '3'; - mockJiraClient.projectKeyToProjectId = jest - .fn() - .mockResolvedValueOnce(123456); - mockJiraClient.addNewIssue = jest - .fn() - .mockResolvedValueOnce(createdIssue); - mockJiraClient.findIssue = jest.fn().mockResolvedValueOnce(foundIssue); - mockJiraClient.addAttachmentOnIssue = jest.fn().mockResolvedValueOnce({}); - - mockS3Client.getObject = jest.fn().mockImplementation(() => ({ - promise: () => - Promise.resolve({ - Body: JSON.stringify(actionProperties), - }), - })); - - actionProperties = { - classification: 'Task', - project: String(projectId), - summary: 'The Summary', - additionalFields: { description: issueDescriptionADF }, - }; - }); - - afterEach(() => { - if (storedActionData) { - expect(mockS3Client.getObject).toHaveBeenCalledWith({ - Bucket: 'jupiterone-test-jupiter-integration-jira-actions', - Key: 'action/data/key', - }); - expect(mockS3Client.getObject).toHaveBeenCalledTimes(1); - } else { - expect(mockS3Client.getObject).toHaveBeenCalledTimes(0); - } - - jest.resetAllMocks(); - }); - - test('uses project ID as provided', async () => { - actionProperties.project = String(projectId); - const issue = await createJiraIssue(mockJiraClient, mockS3Client, { - properties: getActionPropertiesToPass(), - }); - - expect(mockJiraClient.projectKeyToProjectId).not.toHaveBeenCalled(); - expect(mockJiraClient.addNewIssue).toHaveBeenCalledWith( - expect.objectContaining({ - projectId, - }), - ); - - expect(issue).toBe(foundIssue); - }); - - test('converts project key to project ID', async () => { - actionProperties.project = projectKey; - const issue = await createJiraIssue(mockJiraClient, mockS3Client, { - properties: getActionPropertiesToPass(), - }); - - expect(mockJiraClient.projectKeyToProjectId).toHaveBeenCalledWith( - projectKey, - ); - expect(mockJiraClient.addNewIssue).toHaveBeenCalledWith( - expect.objectContaining({ - projectId, - }), - ); - - expect(issue).toBe(foundIssue); - }); - - test('uses description ADF for V3 API', async () => { - mockJiraClient.apiVersion = 3; - - const issue = await createJiraIssue(mockJiraClient, mockS3Client, { - properties: getActionPropertiesToPass(), - }); - - expect(mockJiraClient.addNewIssue).toHaveBeenCalledWith({ - projectId, - issueTypeName: actionProperties.classification, - summary: actionProperties.summary, - additionalFields: { - description: issueDescriptionADF, - }, - }); - - expect(mockJiraClient.findIssue).toHaveBeenCalledWith(createdIssue.key); - expect(issue).toBe(foundIssue); - }); - - test('converts description ADF for V2 API', async () => { - mockJiraClient.apiVersion = '2'; - - const issue = await createJiraIssue(mockJiraClient, mockS3Client, { - properties: getActionPropertiesToPass(), - }); - - expect(mockJiraClient.addNewIssue).toHaveBeenCalledWith({ - projectId, - issueTypeName: actionProperties.classification, - summary: actionProperties.summary, - additionalFields: { - description: issueDescriptionText, - }, - }); - - expect(mockJiraClient.findIssue).toHaveBeenCalledWith(createdIssue.key); - expect(issue).toBe(foundIssue); - }); - - test('does not try to create an attachment for a normal sized description', async () => { - mockJiraClient.apiVersion = '3'; - - const issue = await createJiraIssue(mockJiraClient, mockS3Client, { - properties: getActionPropertiesToPass(), - }); - - // Should not create attachments unless absolutely necessary - expect(mockJiraClient.addAttachmentOnIssue).not.toHaveBeenCalled(); - expect(issue).toBe(foundIssue); - }); - - test('should add the description as an attachment if it is too large', async () => { - mockJiraClient.apiVersion = '3'; - actionProperties.additionalFields = { description: largeAdf }; - - const issue = await createJiraIssue(mockJiraClient, mockS3Client, { - properties: getActionPropertiesToPass(), - }); - expect(mockJiraClient.addAttachmentOnIssue).toHaveBeenCalled(); - - // Should not create attachments unless absolutely necessary - expect(mockJiraClient.addAttachmentOnIssue).toHaveBeenCalledWith( - expect.objectContaining({ - issueId: createdIssue.id, - attachmentContent: expect.any(String), - }), - ); - expect(issue).toBe(foundIssue); - }); - }, -); - -describe(transitionJiraIssue, () => { - const mockJiraClient = {} as JiraClient; - - const issueKey = 'PROJ-42'; - const transitionId = '42'; - - test('should find transition by transition name and send', async () => { - const transition: IssueTransition = { - id: transitionId, - name: 'Answer', - } as any; - - const mockIssue = { transitions: [transition] }; - - mockJiraClient.findIssue = jest.fn().mockResolvedValueOnce(mockIssue); - mockJiraClient.transitionIssue = jest - .fn() - .mockResolvedValueOnce(Promise.resolve()); - - const actionProperties: TransitionIssueActionProperties = { - issueKey, - transitionName: transition.name, - }; - - const issue = await transitionJiraIssue(mockJiraClient, { - properties: actionProperties, - }); - - expect(mockJiraClient.findIssue).toHaveBeenCalledWith(issueKey); - expect(mockJiraClient.transitionIssue).toHaveBeenCalledWith({ - issueId: issueKey, - transitionName: transition.name, - statusName: undefined, - }); - - expect(issue).toBe(mockIssue); - }); - - test('should find transition by target status name and send', async () => { - const transition = { - id: transitionId, - name: 'Answer', - to: { - name: 'Answered', - }, - } as IssueTransition; - - const mockIssue = { transitions: [transition] }; - - mockJiraClient.findIssue = jest.fn().mockResolvedValueOnce(mockIssue); - mockJiraClient.transitionIssue = jest - .fn() - .mockResolvedValueOnce(Promise.resolve()); - - const actionProperties: TransitionIssueActionProperties = { - issueKey, - statusName: transition.to.name, - }; - - const issue = await transitionJiraIssue(mockJiraClient, { - properties: actionProperties, - }); - - expect(mockJiraClient.findIssue).toHaveBeenCalledWith(issueKey); - expect(mockJiraClient.transitionIssue).toHaveBeenCalledWith({ - issueId: issueKey, - transitionName: undefined, - statusName: transition.to.name, - }); - - expect(issue).toBe(mockIssue); - }); - - test('should throw if transition target status not found', async () => { - const transition = { - id: transitionId, - name: 'Answer', - to: { - name: 'Answered', - }, - } as IssueTransition; - - const mockIssue = { transitions: [transition] }; - - mockJiraClient.transitionIssue = JiraClient.prototype.transitionIssue; - mockJiraClient['client'] = { - findIssue: jest.fn().mockResolvedValueOnce(mockIssue), - } as any; - - const actionProperties: TransitionIssueActionProperties = { - issueKey, - statusName: 'Not Answered', - }; - - await expect( - transitionJiraIssue(mockJiraClient, { - properties: actionProperties, - }), - ).rejects.toThrow( - `Unable to find transition for issue ${issueKey} to status "${actionProperties.statusName}"`, - ); - }); - - test('should throw if transition name not found', async () => { - const transition = { - id: transitionId, - name: 'Answer', - to: { - name: 'Answered', - }, - } as IssueTransition; - - const mockIssue = { transitions: [transition] }; - - mockJiraClient.transitionIssue = JiraClient.prototype.transitionIssue; - mockJiraClient['client'] = { - findIssue: jest.fn().mockResolvedValueOnce(mockIssue), - } as any; - - const actionProperties: TransitionIssueActionProperties = { - issueKey, - transitionName: 'Not Answer', - }; - - await expect( - transitionJiraIssue(mockJiraClient, { - properties: actionProperties, - }), - ).rejects.toThrow( - `Unable to find transition for issue ${issueKey} named "${actionProperties.transitionName}"`, - ); - }); -}); diff --git a/src/actions.ts b/src/actions.ts deleted file mode 100644 index c2d2478..0000000 --- a/src/actions.ts +++ /dev/null @@ -1,305 +0,0 @@ -import { S3 } from 'aws-sdk'; -import { - Issue, - IssueFields, - IssueTypeName, - JiraApiVersion, - JiraClient, - JiraProjectId, - JiraProjectKey, -} from './jira'; -import { markdownToADF } from './utils/markdownToADF'; - -const ISSUE_DESCRIPTION_CHARACTER_LIMIT = 32767; -const DESCRIPTION_WHEN_TOO_LONG = - 'The description exceeded the maximum length allowed by Jira, so JupiterOne has attached the contents as a file to this issue.'; -const jupiteroneEnv = process.env.JUPITERONE_ENVIRONMENT; -const jiraActionsBucket = 'jupiter-integration-jira-actions'; - -/** - * The structure of the `properties` data provided by the JupiterOne Alert Rules - * Jira action. - * - * @see createJiraIssue - */ -export type CreateIssueActionProperties = - | (FullCreateIssueActionProperties & { - storedActionData?: false; - }) - | { - storedActionData: true; - actionDataS3Key: string; - }; - -export type TransitionIssueActionProperties = { - issueKey: string; - statusName?: string; - transitionName?: string; -}; - -type FullCreateIssueActionProperties = { - project: JiraProjectKey; - summary: string; - classification: IssueTypeName; - additionalFields?: IssueFields; -}; - -/** - * A utility function created for use by the managed runtime. - * - * The JupiterOne Alert Rules Jira action will submit - * `CreateIssueActionProperties`. The `additionalFields.description` property is - * expected to be provided as an Atlassian Document Format (ADF) structure with - * a single `paragraph.text` value. When the `JiraClient` is configured with - * `apiVersion: '2'`, `additionalFields.description` will be converted to a - * simple string containing only that value. - */ -export async function createJiraIssue( - jiraClient: JiraClient, - s3Client: S3, - action: { properties: CreateIssueActionProperties; [k: string]: any }, -): Promise { - const actionProperties = action.properties.storedActionData - ? await getStoredActionData(s3Client, action.properties.actionDataS3Key) - : action.properties; - - const { - summary, - classification: issueTypeName, - project, - additionalFields, - } = actionProperties; - - const projectId = await getProjectIdForProjectKey(jiraClient, project); - - // Check to see if description is too long, if it is, strip it out and put a placeholder - // in - const descriptionOverCharacterLimit = isDescriptionOverCharacterLimit( - jiraClient.apiVersion, - additionalFields, - ); - - const { - description: additionalFieldsDescription, - ...additionalFieldsWithoutDescription - } = additionalFields ?? {}; - - const newIssue = await jiraClient.addNewIssue({ - summary, - projectId, - issueTypeName, - additionalFields: normalizeIssueFields( - jiraClient.apiVersion, - // Create the issue without a description if the description is over the character limit - descriptionOverCharacterLimit - ? { - ...additionalFieldsWithoutDescription, - description: DESCRIPTION_WHEN_TOO_LONG, - } - : additionalFields, - ), - }); - - if (descriptionOverCharacterLimit) { - // We need to take the description that was too long for the description field, and upload it as an - // attachment to the issue we just created - await jiraClient.addAttachmentOnIssue({ - issueId: newIssue.id, - attachmentContent: getAttachmentContentFromDescription( - additionalFieldsDescription, - ), - }); - } - - // return the issue - return jiraClient.findIssue(newIssue.key); -} - -/** - * A utility function created for use by the managed runtime. - * - * The JupiterOne Alert Rules Jira action output sync will submit - * `TransitionIssueActionProperties`. Only one of the `statusName` or `transitionName` - * properties should be specified. - */ -export async function transitionJiraIssue( - jiraClient: JiraClient, - action: { properties: TransitionIssueActionProperties; [k: string]: any }, -): Promise { - const { issueKey: issueId, statusName, transitionName } = action.properties; - - await jiraClient.transitionIssue({ issueId, statusName, transitionName }); - - return jiraClient.findIssue(issueId); -} - -function isValidCreateIssueActionProperties( - actionProperties: any, -): actionProperties is FullCreateIssueActionProperties { - if (!actionProperties) { - return false; - } - const { project, summary, classification } = actionProperties; - return !!project && !!summary && !!classification; -} - -async function getStoredActionData( - s3Client: S3, - actionDataS3Key: string, -): Promise { - if (!jupiteroneEnv) { - throw new Error('Environment variable JUPITERONE_ENVIRONMENT must be set.'); - } - const { Body: s3ObjectBody } = await s3Client - .getObject({ - Bucket: `${jupiteroneEnv}-${jiraActionsBucket}`, - Key: actionDataS3Key, - }) - .promise(); - - if (!s3ObjectBody) { - throw new Error('Could not fetch action data.'); - } - - const actionProperties = JSON.parse( - s3ObjectBody.toString('utf-8'), - ) as unknown; - if (!isValidCreateIssueActionProperties(actionProperties)) { - throw new Error( - 'Fetched action data does not contain expected properties.', - ); - } - return actionProperties; -} - -async function getProjectIdForProjectKey( - client: JiraClient, - project: string, -): Promise { - const projectId = Number(project); - - if (!isNaN(projectId)) { - if (project.includes('.')) { - throw new Error(`Invalid project id provided (projectId=${project})`); - } - - if (!Number.isInteger(projectId)) { - throw new Error(`Invalid project id provided (projectId=${projectId})`); - } - - return projectId; - } - - return client.projectKeyToProjectId(project); -} - -function isDescriptionOverCharacterLimit( - apiVersion: JiraApiVersion, - issueFields: IssueFields | undefined, -): boolean { - if (!issueFields) { - // If no fields, can't be over the character limit - return false; - } - - const { description } = issueFields; - - if (!description) { - // If no description, can't be over the character limit - return false; - } - - const normalizedDescription = getNormalizedDescription( - apiVersion, - description, - ); - - // The normalized description is of type any, so we need to make sure we convert - // it to a string before doing any string length calculations - const stringifiedDescription = JSON.stringify(normalizedDescription); - // Need to be very defensive here since it is all typed as any - if (!stringifiedDescription) { - return false; - } - - // There is a chance that since we are doing a stringify, it could add some filler characters - // to the original string, and the input could actually be less than the threshold. However, - // since this is all typed as any (and could be ADF, JSON, Markdown, or a string), it is a trade-off - // we have to be okay with. - return stringifiedDescription.length >= ISSUE_DESCRIPTION_CHARACTER_LIMIT; -} - -/** - * Gets the correct version of the description based on the API version. - * Can return ADF, Markdown, a string, or undefined - */ -function getNormalizedDescription( - apiVersion: JiraApiVersion, - description: IssueFields[keyof IssueFields], -) { - const isADF = isAlertRulesDescriptionADF(description); - if (isADF) { - const alertRulesDescription = getAlertRulesDescription(description); - if (apiVersion === '2') { - return alertRulesDescription; - } - if (apiVersion === '3') { - return markdownToADF(alertRulesDescription); - } - } else { - // Support non-ADF description field - if (apiVersion === '3') { - return markdownToADF(description); - } - } -} - -function normalizeIssueFields( - apiVersion: JiraApiVersion, - issueFields: IssueFields | undefined, -): IssueFields { - const normalizedFields: IssueFields = { ...issueFields }; - const normalizedDescription = getNormalizedDescription( - apiVersion, - normalizedFields.description, - ); - if (normalizedDescription) { - normalizedFields.description = normalizedDescription; - } - - return normalizedFields; -} - -/** - * Converts the passed in description into a format suitable for a JIRA - * attachment. The output needs to be a string, so this function takes - * the different possible input formats for a description, and ensures - * the output is String-like - */ -function getAttachmentContentFromDescription(description: any) { - if (isAlertRulesDescriptionADF(description)) { - // For ADF, just pull out the text from the ADF node - return getAlertRulesDescription(description); - } else { - if (typeof description !== 'string') { - // stringify all non-string objects - return JSON.stringify(description); - } - } - - return description; -} - -function isAlertRulesDescriptionADF(description?: any): boolean { - return !!( - description && - description.type === 'doc' && - description.content.length === 1 && - description.content[0].content.length === 1 && - description.content[0].content[0].type === 'text' - ); -} - -function getAlertRulesDescription(description: any): string | undefined { - return description.content[0].content[0].text; -} diff --git a/src/index.ts b/src/index.ts index 34d8130..4c576ea 100644 --- a/src/index.ts +++ b/src/index.ts @@ -16,13 +16,6 @@ export const invocationConfig: IntegrationInvocationConfig = ingestionConfig, }; -// -// Changes to the types and functions below must be tested with -// `@jupiterone/jupiter-integration-jira`! This is a transitional design, not a -// recommended pattern for other integrations. -// -export { CreateIssueActionProperties, createJiraIssue } from './actions'; - export { JiraClient } from './jira'; export { diff --git a/yarn.lock b/yarn.lock index 2879ee0..c08ff4d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3535,32 +3535,11 @@ auto@^10.37.4: terminal-link "^2.1.1" tslib "2.1.0" -available-typed-arrays@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" - integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== - await-to-js@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/await-to-js/-/await-to-js-3.0.0.tgz#70929994185616f4675a91af6167eb61cc92868f" integrity sha512-zJAaP9zxTcvTHRlejau3ZOY4V7SRpiByf3/dxx2uyKxxor19tpmpV2QRsTKikckwhaPmr2dVpxxMr7jOCYVp5g== -aws-sdk@^2.184.0: - version "2.1291.0" - resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1291.0.tgz#315e64dead4a1222726a55348bb2aa332a1917d4" - integrity sha512-iM82Md2Wb29MZ72BpNF4YeIHtkJTyw+JMGXJG48Dwois2Rq7rLcriX6NN/4Fx4b5EEtUkwAO/wJc+NTHI7QeJw== - dependencies: - buffer "4.9.2" - events "1.1.1" - ieee754 "1.1.13" - jmespath "0.16.0" - querystring "0.2.0" - sax "1.2.1" - url "0.10.3" - util "^0.12.4" - uuid "8.0.0" - xml2js "0.4.19" - aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" @@ -3668,7 +3647,7 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== -base64-js@^1.0.2, base64-js@^1.3.1: +base64-js@^1.3.1: version "1.5.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== @@ -3836,15 +3815,6 @@ buffer-from@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== -buffer@4.9.2: - version "4.9.2" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8" - integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg== - dependencies: - base64-js "^1.0.2" - ieee754 "^1.1.4" - isarray "^1.0.0" - buffer@^5.5.0: version "5.7.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" @@ -3900,7 +3870,7 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" -call-bind@^1.0.0, call-bind@^1.0.2: +call-bind@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== @@ -4810,11 +4780,6 @@ eventemitter3@^4.0.4: resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== -events@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" - integrity sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw== - execa@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" @@ -5178,13 +5143,6 @@ follow-redirects@^1.14.9: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== -for-each@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" - integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== - dependencies: - is-callable "^1.1.3" - for-in@^1.0.1, for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" @@ -5326,7 +5284,7 @@ get-folder-size@^2.0.1: gar "^1.0.4" tiny-each-async "2.0.3" -get-intrinsic@^1.0.2, get-intrinsic@^1.1.3: +get-intrinsic@^1.0.2: version "1.1.3" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.3.tgz#063c84329ad93e83893c7f4f243ef63ffa351385" integrity sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A== @@ -5489,13 +5447,6 @@ globby@^7.1.1: pify "^3.0.0" slash "^1.0.0" -gopd@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" - integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== - dependencies: - get-intrinsic "^1.1.3" - graceful-fs@^4.1.15, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.9: version "4.2.10" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" @@ -5546,18 +5497,11 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-symbols@^1.0.2, has-symbols@^1.0.3: +has-symbols@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== -has-tostringtag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" - integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== - dependencies: - has-symbols "^1.0.2" - has-value@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" @@ -5689,12 +5633,7 @@ iconv-lite@0.4.24, iconv-lite@^0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" -ieee754@1.1.13: - version "1.1.13" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" - integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== - -ieee754@^1.1.13, ieee754@^1.1.4, ieee754@^1.2.1: +ieee754@^1.1.13, ieee754@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== @@ -5841,14 +5780,6 @@ is-accessor-descriptor@^1.0.0: dependencies: kind-of "^6.0.0" -is-arguments@^1.0.4: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" - integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" @@ -5866,11 +5797,6 @@ is-buffer@^1.1.5: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== -is-callable@^1.1.3: - version "1.2.7" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" - integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== - is-core-module@^2.9.0: version "2.11.0" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144" @@ -5937,13 +5863,6 @@ is-generator-fn@^2.0.0: resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== -is-generator-function@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" - integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== - dependencies: - has-tostringtag "^1.0.0" - is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" @@ -6017,17 +5936,6 @@ is-stream@^2.0.0: resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== -is-typed-array@^1.1.10, is-typed-array@^1.1.3: - version "1.1.10" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.10.tgz#36a5b5cb4189b575d1a3e4b08536bfb485801e3f" - integrity sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.0" - is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" @@ -6055,7 +5963,7 @@ is-windows@^1.0.1, is-windows@^1.0.2: resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== -isarray@1.0.0, isarray@^1.0.0: +isarray@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== @@ -6604,11 +6512,6 @@ jira-client@^7.1.0: request "^2.88.0" request-promise "^4.1.1" -jmespath@0.16.0: - version "0.16.0" - resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.16.0.tgz#b15b0a85dfd4d930d43e69ed605943c802785076" - integrity sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw== - js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -7889,11 +7792,6 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" -punycode@1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" - integrity sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw== - punycode@^2.1.0, punycode@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" @@ -7916,11 +7814,6 @@ qs@~6.5.2: resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== -querystring@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" - integrity sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g== - querystringify@^2.1.1: version "2.2.0" resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" @@ -8323,16 +8216,6 @@ safe-regex@^1.1.0: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sax@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" - integrity sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA== - -sax@>=0.6.0: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== - semver-compare@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" @@ -9193,14 +9076,6 @@ url-parse@^1.5.10, url-parse@^1.5.3: querystringify "^2.1.1" requires-port "^1.0.0" -url@0.10.3: - version "0.10.3" - resolved "https://registry.yarnpkg.com/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64" - integrity sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ== - dependencies: - punycode "1.3.2" - querystring "0.2.0" - use@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" @@ -9223,27 +9098,11 @@ util-deprecate@^1.0.1: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== -util@^0.12.4: - version "0.12.5" - resolved "https://registry.yarnpkg.com/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc" - integrity sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA== - dependencies: - inherits "^2.0.3" - is-arguments "^1.0.4" - is-generator-function "^1.0.7" - is-typed-array "^1.1.3" - which-typed-array "^1.1.2" - utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== -uuid@8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.0.0.tgz#bc6ccf91b5ff0ac07bbcdbf1c7c4e150db4dbb6c" - integrity sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw== - uuid@^3.3.2: version "3.4.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" @@ -9319,18 +9178,6 @@ which-pm-runs@^1.0.0: resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.1.0.tgz#35ccf7b1a0fce87bd8b92a478c9d045785d3bf35" integrity sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA== -which-typed-array@^1.1.2: - version "1.1.9" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.9.tgz#307cf898025848cf995e795e8423c7f337efbde6" - integrity sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.0" - is-typed-array "^1.1.10" - which@^1.2.14: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" @@ -9389,19 +9236,6 @@ write-file-atomic@^4.0.2: imurmurhash "^0.1.4" signal-exit "^3.0.7" -xml2js@0.4.19: - version "0.4.19" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" - integrity sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q== - dependencies: - sax ">=0.6.0" - xmlbuilder "~9.0.1" - -xmlbuilder@~9.0.1: - version "9.0.7" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" - integrity sha512-7YXTQc3P2l9+0rjaUbLwMKRhtmwg1M1eDf6nag7urC7pIPYLD9W/jmzQ4ptRSUbodw5S0jfoGTflLemQibSpeQ== - xtend@~2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-2.1.2.tgz#6efecc2a4dad8e6962c4901b337ce7ba87b5d28b"