From 6da3f00cdab9f36c84ded35190d534575b8711b0 Mon Sep 17 00:00:00 2001 From: Neil Mathew Maliackal Date: Thu, 14 Nov 2024 16:00:21 +0530 Subject: [PATCH 1/6] fix(@W-17233341): changes for minting JWT and SFAP endpoints --- src/commands/data-seeding/generate/index.ts | 24 ++++++++--- src/commands/data-seeding/migrate/index.ts | 24 ++++++++--- src/utils/api.ts | 47 +++++++++++++++++---- 3 files changed, 74 insertions(+), 21 deletions(-) diff --git a/src/commands/data-seeding/generate/index.ts b/src/commands/data-seeding/generate/index.ts index 4f308c8..b52bdfc 100644 --- a/src/commands/data-seeding/generate/index.ts +++ b/src/commands/data-seeding/generate/index.ts @@ -8,7 +8,7 @@ import { SfCommand, Flags } from '@salesforce/sf-plugins-core'; import { Messages, PollingClient, SfError, StatusResult } from '@salesforce/core'; import { Duration } from '@salesforce/kit'; -import { initiateDataSeed, pollSeedStatus, PollSeedResponse } from '../../../utils/api.js'; +import { initiateDataSeed, pollSeedStatus, PollSeedResponse, initiateJWTMint } from '../../../utils/api.js' import { getSeedGenerateMso, getSeedGenerateStage as getStage } from '../../../utils/mso.js'; import { DataSeedingGenerateResult } from '../../../utils/types.js'; import { GenerateRequestCache } from '../../../utils/cache.js'; @@ -23,12 +23,12 @@ export default class DataSeedingGenerate extends SfCommand { const { flags } = await this.parse(DataSeedingGenerate); - const { async, 'config-file': configFile, 'source-org': sourceOrg, 'target-org': targetOrg, wait } = flags; - - const { request_id: jobId } = await initiateDataSeed(configFile, 'data-generation'); - + const { async, 'config-file': configFile, 'source-org': srcOrgObj, 'target-org': tgtOrgObj, wait } = flags; + + const sourceOrg = srcOrgObj.getOrgId(); + const srcAccessToken = srcOrgObj.getConnection().accessToken as string; + const srcOrgInstUrl = srcOrgObj.getConnection().instanceUrl as string; + + const targetOrg = tgtOrgObj.getOrgId(); + const tgtAccessToken = tgtOrgObj.getConnection().accessToken as string; + const tgtOrgInstUrl = tgtOrgObj.getConnection().instanceUrl as string; + + //Fetch Valid JWT with Data Seed Org Perm + const { jwt: jwtValue} = await initiateJWTMint(srcOrgInstUrl,srcAccessToken,tgtOrgInstUrl,tgtAccessToken ); + this.log("\nValid JWT Token Fetched."); + const { request_id: jobId } = await initiateDataSeed(configFile, 'data-generation',jwtValue); const reportMessage = messages.getMessage('report.suggestion', [jobId]); if (!jobId) throw new Error('Failed to receive job id'); diff --git a/src/commands/data-seeding/migrate/index.ts b/src/commands/data-seeding/migrate/index.ts index 7a817bd..143d733 100644 --- a/src/commands/data-seeding/migrate/index.ts +++ b/src/commands/data-seeding/migrate/index.ts @@ -8,7 +8,7 @@ import { SfCommand, Flags } from '@salesforce/sf-plugins-core'; import { Duration } from '@salesforce/kit'; import { Messages, PollingClient, StatusResult, SfError } from '@salesforce/core'; -import { initiateDataSeed, PollSeedResponse, pollSeedStatus } from '../../../utils/api.js'; +import { initiateDataSeed, PollSeedResponse, pollSeedStatus, initiateJWTMint } from '../../../utils/api.js'; import { DataSeedingMigrateResult } from '../../../utils/types.js'; import { getSeedMigrateMso, getSeedMigrateStage as getStage } from '../../../utils/mso.js'; import { MigrateRequestCache } from '../../../utils/cache.js'; @@ -23,12 +23,12 @@ export default class DataSeedingMigrate extends SfCommand { const { flags } = await this.parse(DataSeedingMigrate); - const { async, 'config-file': configFile, 'source-org': sourceOrg, 'target-org': targetOrg, wait } = flags; - - const { request_id: jobId } = await initiateDataSeed(configFile, 'data-copy'); + const { async, 'config-file': configFile, 'source-org': sourceOrgObj, 'target-org': targetOrgObj, wait } = flags; + + const sourceOrg = sourceOrgObj.getOrgId(); + const srcAccessToken = sourceOrgObj.getConnection().accessToken as string; + const srcOrgInstUrl = sourceOrgObj.getConnection().instanceUrl as string; + + const targetOrg = targetOrgObj.getOrgId(); + const tgtAccessToken = targetOrgObj.getConnection().accessToken as string; + const tgtOrgInstUrl = targetOrgObj.getConnection().instanceUrl as string; + + //Fetch Valid JWT with Data Seed Org Perm + const { jwt: jwtValue} = await initiateJWTMint(srcOrgInstUrl,srcAccessToken,tgtOrgInstUrl,tgtAccessToken); + this.log("\nValid JWT Token Fetched."); + + const { request_id: jobId } = await initiateDataSeed(configFile, 'data-copy',jwtValue); if (!jobId) throw new Error('Failed to receive job id'); diff --git a/src/utils/api.ts b/src/utils/api.ts index 62b2d26..835a395 100644 --- a/src/utils/api.ts +++ b/src/utils/api.ts @@ -14,6 +14,9 @@ import { SfError, Logger } from '@salesforce/core'; export type SeedResponse = { request_id: string; }; +export type ServletResponse = { + jwt: string; +}; export type PollSeedResponse = { execution_end_time: string; @@ -26,7 +29,8 @@ export type PollSeedResponse = { export type DataSeedingOperation = 'data-generation' | 'data-copy'; -const baseUrl = process.env.SF_DATA_SEEDING_URL ?? 'https://data-seed-scratchpad5.sfdc-3vx9f4.svc.sfdcfc.net'; +// TODO Change to SFAP Endpoint +const baseUrl = process.env.SF_DATA_SEEDING_URL ?? 'https://data-seed-gid.sfdc-yfeipo.svc.sfdcfc.net'; const csrfUrl = `${baseUrl}/get-csrf-token`; const seedUrl = `${baseUrl}/data-seed`; const pollUrl = `${baseUrl}/status`; @@ -44,23 +48,23 @@ export const getCsrfToken = (cookieJar: CookieJar): string => { return csrfToken; }; -export const initiateDataSeed = async (config: string, operation: DataSeedingOperation): Promise => { - const cookieJar = await getCookieJar(); - const csrf = getCsrfToken(cookieJar); - +export const initiateDataSeed = async (config: string, operation: DataSeedingOperation, jwt: string): Promise => { + //const cookieJar = await getCookieJar(); + //const csrf = getCsrfToken(cookieJar); const form = new FormData(); form.append('config_file', fs.createReadStream(config)); + // TODO : Remove credential file once SFAP is active and dataseed endpoint accepts orgurl and token form.append('credentials_file', fs.createReadStream('ignore/credentials.txt')); form.append('operation', operation); - // TODO: Update to use .json() instead of JSON.parse once the Error response is changed to be JSON // Update the return type as well const response = await got.post(seedUrl, { throwHttpErrors: false, - cookieJar, + //cookieJar, headers: { ...form.getHeaders(), - 'X-CSRFToken': csrf, + // 'X-CSRFToken': csrf, + 'Authorization': 'Bearer '+jwt, }, body: form, }); @@ -72,6 +76,33 @@ export const initiateDataSeed = async (config: string, operation: DataSeedingOpe return JSON.parse(response.body) as SeedResponse; }; +export const initiateJWTMint = async (src_org_url: string, src_access_token: string, tgt_org_url: string, tgt_access_token: string ): Promise => { + + const src_servlet_url = src_org_url+'/dataseed/auth' + const response_src = await got.post(src_servlet_url, { + throwHttpErrors: false, + headers: { + 'Authorization': 'Bearer '+src_access_token, + }, + }); + + if (response_src.statusCode !== 200) { + const tgt_servlet_url = tgt_org_url+'/dataseed/auth' + const response_tgt = await got.post(tgt_servlet_url, { + throwHttpErrors: false, + headers: { + 'Authorization': 'Bearer '+tgt_access_token, + }, + }); + if (response_tgt.statusCode !== 200) { + throw new SfError(`Org permission for data seed not found in source & target org.\nSource Response: Error Code : ${response_src.statusCode} - ${response_src.body}. \nTarget Response: Error Code : ${response_tgt.statusCode} - ${response_tgt.body}`); + } + return JSON.parse(response_tgt.body) as ServletResponse; + } + + return JSON.parse(response_src.body) as ServletResponse; +}; + export const pollSeedStatus = async (jobId: string): Promise => { const logger = await Logger.child('PollSeedStatus'); From d1eac950abf3c08bcb3529013b098c51200fb752 Mon Sep 17 00:00:00 2001 From: Neil Mathew Maliackal Date: Thu, 14 Nov 2024 16:09:45 +0530 Subject: [PATCH 2/6] fix(@W-17233341): changes for minting JWT and SFAP endpoints --- README.md | 10 ++--- src/commands/data-seeding/generate/index.ts | 17 ++++---- src/commands/data-seeding/migrate/index.ts | 15 +++---- src/utils/api.ts | 48 +++++++++++++-------- 4 files changed, 49 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index e73207e..4fe0815 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # plugin-data-seeding -[![NPM](https://img.shields.io/npm/v/@salesforce/plugin-data-seeding.svg?label=@salesforce/plugin-data-seeding)](https://www.npmjs.com/package/@salesforce/plugin-data-seeding) [![Downloads/week](https://img.shields.io/npm/dw/@salesforce/plugin-data-seeding.svg)](https://npmjs.org/package/@salesforce/plugin-data-seeding) [![License](https://img.shields.io/badge/License-BSD%203--Clause-brightgreen.svg)](https://raw.githubusercontent.com/salesforcecli/plugin-data-seeding/main/LICENSE.txt) +[![NPM](https://img.shields.io/npm/v/@salesforce/plugin-data-seeding.svg?label=@salesforce/plugin-data-seeding)](https://www.npmjs.com/package/@salesforce/plugin-data-seeding) [![Downloads/week](https://img.shields.io/npm/dw/@salesforce/plugin-data-seeding.svg)](https://npmjs.org/package/@salesforce/plugin-data-seeding) [![License](https://img.shields.io/badge/License-BSD%203--Clause-brightgreen.svg)](https://raw.githubusercontent.com/salesforcecli/plugin-data-seeding/refs/heads/main/LICENSE.txt) ## Using the template @@ -166,7 +166,7 @@ EXAMPLES ./config/seed-config.json --wait 5 ``` -_See code: [src/commands/data-seeding/generate/index.ts](https://github.com/salesforcecli/plugin-data-seeding/blob/v1.0.10/src/commands/data-seeding/generate/index.ts)_ +_See code: [src/commands/data-seeding/generate/index.ts](https://github.com/salesforcecli/plugin-data-seeding/blob/main/src/commands/data-seeding/generate/index.ts)_ ## `sf data-seeding generate report` @@ -201,7 +201,7 @@ EXAMPLES $ sf data-seeding generate report --use-most-recent ``` -_See code: [src/commands/data-seeding/generate/report.ts](https://github.com/salesforcecli/plugin-data-seeding/blob/v1.0.10/src/commands/data-seeding/generate/report.ts)_ +_See code: [src/commands/data-seeding/generate/report.ts](https://github.com/salesforcecli/plugin-data-seeding/blob/main/src/commands/data-seeding/generate/report.ts)_ ## `sf data-seeding migrate` @@ -254,7 +254,7 @@ EXAMPLES ./config/data-seed.json --wait 5 ``` -_See code: [src/commands/data-seeding/migrate/index.ts](https://github.com/salesforcecli/plugin-data-seeding/blob/v1.0.10/src/commands/data-seeding/migrate/index.ts)_ +_See code: [src/commands/data-seeding/migrate/index.ts](https://github.com/salesforcecli/plugin-data-seeding/blob/main/src/commands/data-seeding/migrate/index.ts)_ ## `sf data-seeding migrate report` @@ -289,6 +289,6 @@ EXAMPLES $ sf data-seeding migrate report --use-most-recent ``` -_See code: [src/commands/data-seeding/migrate/report.ts](https://github.com/salesforcecli/plugin-data-seeding/blob/v1.0.10/src/commands/data-seeding/migrate/report.ts)_ +_See code: [src/commands/data-seeding/migrate/report.ts](https://github.com/salesforcecli/plugin-data-seeding/blob/main/src/commands/data-seeding/migrate/report.ts)_ diff --git a/src/commands/data-seeding/generate/index.ts b/src/commands/data-seeding/generate/index.ts index b52bdfc..05614d1 100644 --- a/src/commands/data-seeding/generate/index.ts +++ b/src/commands/data-seeding/generate/index.ts @@ -8,7 +8,7 @@ import { SfCommand, Flags } from '@salesforce/sf-plugins-core'; import { Messages, PollingClient, SfError, StatusResult } from '@salesforce/core'; import { Duration } from '@salesforce/kit'; -import { initiateDataSeed, pollSeedStatus, PollSeedResponse, initiateJWTMint } from '../../../utils/api.js' +import { initiateDataSeed, pollSeedStatus, PollSeedResponse, initiateJWTMint } from '../../../utils/api.js'; import { getSeedGenerateMso, getSeedGenerateStage as getStage } from '../../../utils/mso.js'; import { DataSeedingGenerateResult } from '../../../utils/types.js'; import { GenerateRequestCache } from '../../../utils/cache.js'; @@ -56,19 +56,18 @@ export default class DataSeedingGenerate extends SfCommand { const { flags } = await this.parse(DataSeedingGenerate); const { async, 'config-file': configFile, 'source-org': srcOrgObj, 'target-org': tgtOrgObj, wait } = flags; - + const sourceOrg = srcOrgObj.getOrgId(); const srcAccessToken = srcOrgObj.getConnection().accessToken as string; - const srcOrgInstUrl = srcOrgObj.getConnection().instanceUrl as string; + const srcOrgInstUrl = srcOrgObj.getConnection().instanceUrl; const targetOrg = tgtOrgObj.getOrgId(); const tgtAccessToken = tgtOrgObj.getConnection().accessToken as string; - const tgtOrgInstUrl = tgtOrgObj.getConnection().instanceUrl as string; - - //Fetch Valid JWT with Data Seed Org Perm - const { jwt: jwtValue} = await initiateJWTMint(srcOrgInstUrl,srcAccessToken,tgtOrgInstUrl,tgtAccessToken ); - this.log("\nValid JWT Token Fetched."); - const { request_id: jobId } = await initiateDataSeed(configFile, 'data-generation',jwtValue); + const tgtOrgInstUrl = tgtOrgObj.getConnection().instanceUrl; + + // Fetch Valid JWT with Data Seed Org Perm + const { jwt: jwtValue } = await initiateJWTMint(srcOrgInstUrl, srcAccessToken, tgtOrgInstUrl, tgtAccessToken); + const { request_id: jobId } = await initiateDataSeed(configFile, 'data-generation', jwtValue); const reportMessage = messages.getMessage('report.suggestion', [jobId]); if (!jobId) throw new Error('Failed to receive job id'); diff --git a/src/commands/data-seeding/migrate/index.ts b/src/commands/data-seeding/migrate/index.ts index 143d733..cd41ff2 100644 --- a/src/commands/data-seeding/migrate/index.ts +++ b/src/commands/data-seeding/migrate/index.ts @@ -56,20 +56,19 @@ export default class DataSeedingMigrate extends SfCommand { const { flags } = await this.parse(DataSeedingMigrate); const { async, 'config-file': configFile, 'source-org': sourceOrgObj, 'target-org': targetOrgObj, wait } = flags; - + const sourceOrg = sourceOrgObj.getOrgId(); const srcAccessToken = sourceOrgObj.getConnection().accessToken as string; - const srcOrgInstUrl = sourceOrgObj.getConnection().instanceUrl as string; + const srcOrgInstUrl = sourceOrgObj.getConnection().instanceUrl; const targetOrg = targetOrgObj.getOrgId(); const tgtAccessToken = targetOrgObj.getConnection().accessToken as string; - const tgtOrgInstUrl = targetOrgObj.getConnection().instanceUrl as string; - - //Fetch Valid JWT with Data Seed Org Perm - const { jwt: jwtValue} = await initiateJWTMint(srcOrgInstUrl,srcAccessToken,tgtOrgInstUrl,tgtAccessToken); - this.log("\nValid JWT Token Fetched."); + const tgtOrgInstUrl = targetOrgObj.getConnection().instanceUrl; + + // Fetch Valid JWT with Data Seed Org Perm + const { jwt: jwtValue } = await initiateJWTMint(srcOrgInstUrl, srcAccessToken, tgtOrgInstUrl, tgtAccessToken); - const { request_id: jobId } = await initiateDataSeed(configFile, 'data-copy',jwtValue); + const { request_id: jobId } = await initiateDataSeed(configFile, 'data-copy', jwtValue); if (!jobId) throw new Error('Failed to receive job id'); diff --git a/src/utils/api.ts b/src/utils/api.ts index 835a395..274daef 100644 --- a/src/utils/api.ts +++ b/src/utils/api.ts @@ -30,7 +30,7 @@ export type PollSeedResponse = { export type DataSeedingOperation = 'data-generation' | 'data-copy'; // TODO Change to SFAP Endpoint -const baseUrl = process.env.SF_DATA_SEEDING_URL ?? 'https://data-seed-gid.sfdc-yfeipo.svc.sfdcfc.net'; +const baseUrl = process.env.SF_DATA_SEEDING_URL ?? 'https://data-seed-gid.sfdc-yfeipo.svc.sfdcfc.net'; const csrfUrl = `${baseUrl}/get-csrf-token`; const seedUrl = `${baseUrl}/data-seed`; const pollUrl = `${baseUrl}/status`; @@ -48,9 +48,13 @@ export const getCsrfToken = (cookieJar: CookieJar): string => { return csrfToken; }; -export const initiateDataSeed = async (config: string, operation: DataSeedingOperation, jwt: string): Promise => { - //const cookieJar = await getCookieJar(); - //const csrf = getCsrfToken(cookieJar); +export const initiateDataSeed = async ( + config: string, + operation: DataSeedingOperation, + jwt: string +): Promise => { + // const cookieJar = await getCookieJar(); + // const csrf = getCsrfToken(cookieJar); const form = new FormData(); form.append('config_file', fs.createReadStream(config)); // TODO : Remove credential file once SFAP is active and dataseed endpoint accepts orgurl and token @@ -60,11 +64,11 @@ export const initiateDataSeed = async (config: string, operation: DataSeedingOpe // Update the return type as well const response = await got.post(seedUrl, { throwHttpErrors: false, - //cookieJar, + // cookieJar, headers: { ...form.getHeaders(), // 'X-CSRFToken': csrf, - 'Authorization': 'Bearer '+jwt, + Authorization: 'Bearer ' + jwt, }, body: form, }); @@ -76,31 +80,37 @@ export const initiateDataSeed = async (config: string, operation: DataSeedingOpe return JSON.parse(response.body) as SeedResponse; }; -export const initiateJWTMint = async (src_org_url: string, src_access_token: string, tgt_org_url: string, tgt_access_token: string ): Promise => { - - const src_servlet_url = src_org_url+'/dataseed/auth' - const response_src = await got.post(src_servlet_url, { +export const initiateJWTMint = async ( + srcOrgUrl: string, + srcAccessToken: string, + tgtOrgUrl: string, + tgtAccessToken: string +): Promise => { + const srcServletUrl = srcOrgUrl + '/dataseed/auth'; + const responseSrc = await got.post(srcServletUrl, { throwHttpErrors: false, headers: { - 'Authorization': 'Bearer '+src_access_token, + Authorization: 'Bearer ' + srcAccessToken, }, }); - if (response_src.statusCode !== 200) { - const tgt_servlet_url = tgt_org_url+'/dataseed/auth' - const response_tgt = await got.post(tgt_servlet_url, { + if (responseSrc.statusCode !== 200) { + const tgtServletUrl = tgtOrgUrl + '/dataseed/auth'; + const responseTgt = await got.post(tgtServletUrl, { throwHttpErrors: false, headers: { - 'Authorization': 'Bearer '+tgt_access_token, + Authorization: 'Bearer ' + tgtAccessToken, }, }); - if (response_tgt.statusCode !== 200) { - throw new SfError(`Org permission for data seed not found in source & target org.\nSource Response: Error Code : ${response_src.statusCode} - ${response_src.body}. \nTarget Response: Error Code : ${response_tgt.statusCode} - ${response_tgt.body}`); + if (responseTgt.statusCode !== 200) { + throw new SfError( + `Org permission for data seed not found in source & target org.\nSource Response: Error Code : ${responseSrc.statusCode} - ${responseSrc.body}. \nTarget Response: Error Code : ${responseTgt.statusCode} - ${responseTgt.body}` + ); } - return JSON.parse(response_tgt.body) as ServletResponse; + return JSON.parse(responseTgt.body) as ServletResponse; } - return JSON.parse(response_src.body) as ServletResponse; + return JSON.parse(responseSrc.body) as ServletResponse; }; export const pollSeedStatus = async (jobId: string): Promise => { From 2cceecc2408622ca46ef9cf3d195387b7fd94a15 Mon Sep 17 00:00:00 2001 From: Neil Mathew Maliackal Date: Thu, 14 Nov 2024 16:11:53 +0530 Subject: [PATCH 3/6] fix(@W-17233341): changes for minting JWT and SFAP endpoints --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 4fe0815..e73207e 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # plugin-data-seeding -[![NPM](https://img.shields.io/npm/v/@salesforce/plugin-data-seeding.svg?label=@salesforce/plugin-data-seeding)](https://www.npmjs.com/package/@salesforce/plugin-data-seeding) [![Downloads/week](https://img.shields.io/npm/dw/@salesforce/plugin-data-seeding.svg)](https://npmjs.org/package/@salesforce/plugin-data-seeding) [![License](https://img.shields.io/badge/License-BSD%203--Clause-brightgreen.svg)](https://raw.githubusercontent.com/salesforcecli/plugin-data-seeding/refs/heads/main/LICENSE.txt) +[![NPM](https://img.shields.io/npm/v/@salesforce/plugin-data-seeding.svg?label=@salesforce/plugin-data-seeding)](https://www.npmjs.com/package/@salesforce/plugin-data-seeding) [![Downloads/week](https://img.shields.io/npm/dw/@salesforce/plugin-data-seeding.svg)](https://npmjs.org/package/@salesforce/plugin-data-seeding) [![License](https://img.shields.io/badge/License-BSD%203--Clause-brightgreen.svg)](https://raw.githubusercontent.com/salesforcecli/plugin-data-seeding/main/LICENSE.txt) ## Using the template @@ -166,7 +166,7 @@ EXAMPLES ./config/seed-config.json --wait 5 ``` -_See code: [src/commands/data-seeding/generate/index.ts](https://github.com/salesforcecli/plugin-data-seeding/blob/main/src/commands/data-seeding/generate/index.ts)_ +_See code: [src/commands/data-seeding/generate/index.ts](https://github.com/salesforcecli/plugin-data-seeding/blob/v1.0.10/src/commands/data-seeding/generate/index.ts)_ ## `sf data-seeding generate report` @@ -201,7 +201,7 @@ EXAMPLES $ sf data-seeding generate report --use-most-recent ``` -_See code: [src/commands/data-seeding/generate/report.ts](https://github.com/salesforcecli/plugin-data-seeding/blob/main/src/commands/data-seeding/generate/report.ts)_ +_See code: [src/commands/data-seeding/generate/report.ts](https://github.com/salesforcecli/plugin-data-seeding/blob/v1.0.10/src/commands/data-seeding/generate/report.ts)_ ## `sf data-seeding migrate` @@ -254,7 +254,7 @@ EXAMPLES ./config/data-seed.json --wait 5 ``` -_See code: [src/commands/data-seeding/migrate/index.ts](https://github.com/salesforcecli/plugin-data-seeding/blob/main/src/commands/data-seeding/migrate/index.ts)_ +_See code: [src/commands/data-seeding/migrate/index.ts](https://github.com/salesforcecli/plugin-data-seeding/blob/v1.0.10/src/commands/data-seeding/migrate/index.ts)_ ## `sf data-seeding migrate report` @@ -289,6 +289,6 @@ EXAMPLES $ sf data-seeding migrate report --use-most-recent ``` -_See code: [src/commands/data-seeding/migrate/report.ts](https://github.com/salesforcecli/plugin-data-seeding/blob/main/src/commands/data-seeding/migrate/report.ts)_ +_See code: [src/commands/data-seeding/migrate/report.ts](https://github.com/salesforcecli/plugin-data-seeding/blob/v1.0.10/src/commands/data-seeding/migrate/report.ts)_ From 5be21267f252e58d35f01564d4680e2bc477b281 Mon Sep 17 00:00:00 2001 From: Neil Mathew Maliackal Date: Fri, 15 Nov 2024 18:34:08 +0530 Subject: [PATCH 4/6] @W-17233341 - Updating SFAP endpoint, removal of csrf, removal of credential file --- package.json | 5 +- src/commands/data-seeding/generate/index.ts | 10 ++- src/commands/data-seeding/migrate/index.ts | 11 ++- src/utils/api.ts | 89 ++++++++++----------- yarn.lock | 10 --- 5 files changed, 63 insertions(+), 62 deletions(-) diff --git a/package.json b/package.json index 6388b1e..24abf90 100644 --- a/package.json +++ b/package.json @@ -11,15 +11,14 @@ "@salesforce/kit": "^3.2.2", "@salesforce/sf-plugins-core": "^11.3.12", "form-data": "^4.0.1", - "got": "^14.4.3", - "tough-cookie": "^4.1.4" + "got": "^14.4.3" }, "devDependencies": { "@oclif/plugin-command-snapshot": "^5.2.21", "@salesforce/cli-plugins-testkit": "^5.3.35", "@salesforce/dev-scripts": "^10.2.9", - "@types/tough-cookie": "^4.0.5", "@salesforce/plugin-command-reference": "^3.1.32", + "@types/tough-cookie": "^4.0.5", "eslint-plugin-sf-plugin": "^1.20.11", "oclif": "^4.15.14", "ts-node": "^10.9.2", diff --git a/src/commands/data-seeding/generate/index.ts b/src/commands/data-seeding/generate/index.ts index 05614d1..0328495 100644 --- a/src/commands/data-seeding/generate/index.ts +++ b/src/commands/data-seeding/generate/index.ts @@ -67,7 +67,15 @@ export default class DataSeedingGenerate extends SfCommand => { - const cookieJar = new CookieJar(); - await got(csrfUrl, { cookieJar }); - return cookieJar; -}; - -export const getCsrfToken = (cookieJar: CookieJar): string => { - const csrfToken = cookieJar.getCookiesSync(csrfUrl).find((cookie) => cookie.key === 'csrf_token')?.value; - if (!csrfToken) throw new SfError('Failed to obtain CSRF token'); - - return csrfToken; -}; - export const initiateDataSeed = async ( config: string, operation: DataSeedingOperation, - jwt: string + jwt: string, + srcOrgUrl: string, + srcAccessToken: string, + tgtOrgUrl: string, + tgtAccessToken: string ): Promise => { - // const cookieJar = await getCookieJar(); - // const csrf = getCsrfToken(cookieJar); const form = new FormData(); form.append('config_file', fs.createReadStream(config)); - // TODO : Remove credential file once SFAP is active and dataseed endpoint accepts orgurl and token - form.append('credentials_file', fs.createReadStream('ignore/credentials.txt')); form.append('operation', operation); + form.append('source_access_token', srcAccessToken); + form.append('source_instance_url', srcOrgUrl); + form.append('target_access_token', tgtAccessToken); + form.append('target_instance_url', tgtOrgUrl); // TODO: Update to use .json() instead of JSON.parse once the Error response is changed to be JSON // Update the return type as well const response = await got.post(seedUrl, { throwHttpErrors: false, - // cookieJar, headers: { ...form.getHeaders(), - // 'X-CSRFToken': csrf, - Authorization: 'Bearer ' + jwt, + Authorization: `Bearer ${jwt}`, }, body: form, }); @@ -86,31 +76,38 @@ export const initiateJWTMint = async ( tgtOrgUrl: string, tgtAccessToken: string ): Promise => { - const srcServletUrl = srcOrgUrl + '/dataseed/auth'; - const responseSrc = await got.post(srcServletUrl, { - throwHttpErrors: false, - headers: { - Authorization: 'Bearer ' + srcAccessToken, - }, - }); + const srcServletUrl = `${srcOrgUrl}/dataseed/auth`; + const tgtServletUrl = `${tgtOrgUrl}/dataseed/auth`; + + const [responseSrc, responseTgt] = await Promise.all([ + callAuthServlet(srcServletUrl, srcAccessToken), + callAuthServlet(tgtServletUrl, tgtAccessToken), + ]); - if (responseSrc.statusCode !== 200) { - const tgtServletUrl = tgtOrgUrl + '/dataseed/auth'; - const responseTgt = await got.post(tgtServletUrl, { - throwHttpErrors: false, - headers: { - Authorization: 'Bearer ' + tgtAccessToken, - }, - }); - if (responseTgt.statusCode !== 200) { - throw new SfError( - `Org permission for data seed not found in source & target org.\nSource Response: Error Code : ${responseSrc.statusCode} - ${responseSrc.body}. \nTarget Response: Error Code : ${responseTgt.statusCode} - ${responseTgt.body}` - ); - } + if (responseSrc.statusCode === '200') { + return JSON.parse(responseSrc.body) as ServletResponse; + } + + if (responseTgt.statusCode === '200') { return JSON.parse(responseTgt.body) as ServletResponse; } - return JSON.parse(responseSrc.body) as ServletResponse; + throw new SfError( + `Org permission for data seed not found in either the source or target org.\nSource Response: Error Code : ${responseSrc.statusCode} - ${responseSrc.body}. \nTarget Response: Error Code : ${responseTgt.statusCode} - ${responseTgt.body}` + ); +}; + +const callAuthServlet = async (url: string, accessToken: string): Promise => { + const response = await got.post(url, { + throwHttpErrors: false, + headers: { + Authorization: `Bearer ${accessToken}`, + }, + }); + return { + statusCode: response.statusCode.toString(), // Convert to string + body: response.body, + }; }; export const pollSeedStatus = async (jobId: string): Promise => { diff --git a/yarn.lock b/yarn.lock index e33f58b..8cd8ac5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7171,16 +7171,6 @@ tough-cookie@*: universalify "^0.2.0" url-parse "^1.5.3" -tough-cookie@^4.1.4: - version "4.1.4" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.4.tgz#945f1461b45b5a8c76821c33ea49c3ac192c1b36" - integrity sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag== - dependencies: - psl "^1.1.33" - punycode "^2.1.1" - universalify "^0.2.0" - url-parse "^1.5.3" - tr46@~0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" From 2cd57c5df2536f00e7d7cdac606ce863e2bef31d Mon Sep 17 00:00:00 2001 From: Neil Mathew Maliackal Date: Mon, 18 Nov 2024 11:25:43 +0530 Subject: [PATCH 5/6] @W-17233341 - Updating SFAP prod endpoint, adding sourceOrgID body parameter for token update --- src/commands/data-seeding/generate/index.ts | 9 ++++++--- src/commands/data-seeding/generate/report.ts | 2 +- src/commands/data-seeding/migrate/index.ts | 9 ++++++--- src/commands/data-seeding/migrate/report.ts | 2 +- src/utils/api.ts | 15 +++++++++++---- src/utils/mso.ts | 1 + 6 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/commands/data-seeding/generate/index.ts b/src/commands/data-seeding/generate/index.ts index 0328495..3236bad 100644 --- a/src/commands/data-seeding/generate/index.ts +++ b/src/commands/data-seeding/generate/index.ts @@ -74,7 +74,8 @@ export default class DataSeedingGenerate extends SfCommand => { - const response = await pollSeedStatus(jobId); + const { jwt: jwtValue } = await initiateJWTMint(srcOrgInstUrl, srcAccessToken, tgtOrgInstUrl, tgtAccessToken); + const response = await pollSeedStatus(jobId,jwtValue); mso.goto(getStage(response.step), { startTime: response.execution_start_time, @@ -151,7 +153,8 @@ export default class DataSeedingGenerate extends SfCommand => { - const response = await pollSeedStatus(jobId); + const { jwt: jwtValue } = await initiateJWTMint(srcOrgInstUrl, srcAccessToken, tgtOrgInstUrl, tgtAccessToken); + const response = await pollSeedStatus(jobId,jwtValue); mso.goto(getStage(response.step), { startTime: response.execution_start_time, @@ -154,7 +156,8 @@ export default class DataSeedingMigrate extends SfCommand => { const form = new FormData(); form.append('config_file', fs.createReadStream(config)); @@ -52,6 +53,7 @@ export const initiateDataSeed = async ( form.append('source_instance_url', srcOrgUrl); form.append('target_access_token', tgtAccessToken); form.append('target_instance_url', tgtOrgUrl); + form.append('source_org_id',srcOrgId); // TODO: Update to use .json() instead of JSON.parse once the Error response is changed to be JSON // Update the return type as well const response = await got.post(seedUrl, { @@ -59,6 +61,7 @@ export const initiateDataSeed = async ( headers: { ...form.getHeaders(), Authorization: `Bearer ${jwt}`, + 'x-salesforce-region':sfRegion, }, body: form, }); @@ -110,12 +113,16 @@ const callAuthServlet = async (url: string, accessToken: string): Promise => { +export const pollSeedStatus = async (jobId: string, jwt: string): Promise => { const logger = await Logger.child('PollSeedStatus'); // TODO: Update to use .json() instead of JSON.parse once the Error response is changed to be JSON // Update the return type as well - const response = await got.get(`${pollUrl}/${jobId}`, { throwHttpErrors: false }); + const headers = { + Authorization: `Bearer ${jwt}`, + 'x-salesforce-region': sfRegion, + }; + const response = await got.get(`${pollUrl}/${jobId}`, { throwHttpErrors: false, headers }); if (response.statusCode !== 200) { // TODO: Print error body once the Error response is changed to be JSON diff --git a/src/utils/mso.ts b/src/utils/mso.ts index 82a04fd..ccc206c 100644 --- a/src/utils/mso.ts +++ b/src/utils/mso.ts @@ -28,6 +28,7 @@ type MsoGet = string | undefined; // - They have been converted to lowercase for later comparison // The values in this Map are used as the stage names in mso const seedGenerateStagesMap = new Map([ + ['init','Initializing'], ['querying source org', 'Querying Source Org'], ['data generation', 'Data Generation'], ['populating target org', 'Populating Target Org'], From 19b832cec5b29927d7b8d9a9282e090ff52db29b Mon Sep 17 00:00:00 2001 From: Neil Mathew Maliackal Date: Mon, 18 Nov 2024 11:39:03 +0530 Subject: [PATCH 6/6] @W-17233341 - Minor changes for tests --- src/commands/data-seeding/generate/index.ts | 13 +++++++++---- src/commands/data-seeding/generate/report.ts | 2 +- src/commands/data-seeding/migrate/index.ts | 13 +++++++++---- src/commands/data-seeding/migrate/report.ts | 6 +++--- 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/commands/data-seeding/generate/index.ts b/src/commands/data-seeding/generate/index.ts index 3236bad..dd104ef 100644 --- a/src/commands/data-seeding/generate/index.ts +++ b/src/commands/data-seeding/generate/index.ts @@ -101,8 +101,13 @@ export default class DataSeedingGenerate extends SfCommand => { - const { jwt: jwtValue } = await initiateJWTMint(srcOrgInstUrl, srcAccessToken, tgtOrgInstUrl, tgtAccessToken); - const response = await pollSeedStatus(jobId,jwtValue); + const { jwt: jwtValueNew } = await initiateJWTMint( + srcOrgInstUrl, + srcAccessToken, + tgtOrgInstUrl, + tgtAccessToken + ); + const response = await pollSeedStatus(jobId, jwtValueNew); mso.goto(getStage(response.step), { startTime: response.execution_start_time, @@ -153,8 +158,8 @@ export default class DataSeedingGenerate extends SfCommand => { - const { jwt: jwtValue } = await initiateJWTMint(srcOrgInstUrl, srcAccessToken, tgtOrgInstUrl, tgtAccessToken); - const response = await pollSeedStatus(jobId,jwtValue); + const { jwt: jwtValueNew } = await initiateJWTMint( + srcOrgInstUrl, + srcAccessToken, + tgtOrgInstUrl, + tgtAccessToken + ); + const response = await pollSeedStatus(jobId, jwtValueNew); mso.goto(getStage(response.step), { startTime: response.execution_start_time, @@ -156,8 +161,8 @@ export default class DataSeedingMigrate extends SfCommand { @@ -40,7 +40,7 @@ export default class DataSeedingMigrateReport extends SfCommand