Skip to content

Commit

Permalink
create syncOneTrustAssessments and enrichOneTrustAssessment helpers
Browse files Browse the repository at this point in the history
  • Loading branch information
abrantesarthur committed Jan 14, 2025
1 parent 4b428dc commit 13e80e9
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 7 deletions.
5 changes: 2 additions & 3 deletions src/cli-sync-ot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,12 @@ import {
async function main(): Promise<void> {
const { file, fileFormat, hostname, auth, resource, debug } =
parseCliSyncOtArguments();
// use the hostname and auth token to instantiate a client to talk to OneTrust
const oneTrust = createOneTrustGotInstance({ hostname, auth });

try {
// TODO: move to helper function
if (resource === OneTrustPullResource.Assessments) {
// use the hostname and auth token to instantiate a client to talk to OneTrust
const oneTrust = createOneTrustGotInstance({ hostname, auth });

// fetch the list of all assessments in the OneTrust organization
const assessments = await getListOfOneTrustAssessments({ oneTrust });

Expand Down
1 change: 0 additions & 1 deletion src/oneTrust/endpoints/getListOfOneTrustAssessments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ export const getListOfOneTrustAssessments = async ({

const allAssessments: OneTrustAssessment[] = [];

logger.info('Getting list of all assessments from OneTrust...');
while (currentPage < totalPages) {
// eslint-disable-next-line no-await-in-loop
const { body } = await oneTrust.get(
Expand Down
67 changes: 67 additions & 0 deletions src/oneTrust/helpers/enrichOneTrustAssessment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import {
OneTrustAssessment,
OneTrustGetAssessmentResponse,
OneTrustGetRiskResponse,
} from '@transcend-io/privacy-types';
import keyBy from 'lodash/keyBy';
import { OneTrustEnrichedAssessment } from '../codecs';

/**
* Merge the assessment, assessmentDetails, and riskDetails into one object.
*
* @param param - the assessment and risk information
* @returns the assessment enriched with details and risk information
*/
export const enrichOneTrustAssessment = ({
assessment,
assessmentDetails,
riskDetails,
}: {
/** The OneTrust risk details */
riskDetails: OneTrustGetRiskResponse[];
/** The OneTrust assessment as returned from Get List of Assessments endpoint */
assessment: OneTrustAssessment;
/** The OneTrust assessment details */
assessmentDetails: OneTrustGetAssessmentResponse;
}): OneTrustEnrichedAssessment => {
const riskDetailsById = keyBy(riskDetails, 'id');
const { sections, ...restAssessmentDetails } = assessmentDetails;
const sectionsWithEnrichedRisk = sections.map((section) => {
const { questions, ...restSection } = section;
const enrichedQuestions = questions.map((question) => {
const { risks, ...restQuestion } = question;
const enrichedRisks = (risks ?? []).map((risk) => {
const details = riskDetailsById[risk.riskId];
// TODO: missing the risk meta data and links to the assessment
return {
...risk,
description: details.description,
name: details.name,
treatment: details.treatment,
treatmentStatus: details.treatmentStatus,
type: details.type,
state: details.state,
stage: details.stage,
result: details.result,
categories: details.categories,
};
});
return {
...restQuestion,
risks: enrichedRisks,
};
});
return {
...restSection,
questions: enrichedQuestions,
};
});

// combine the two assessments into a single enriched result

return {
...assessment,
...restAssessmentDetails,
sections: sectionsWithEnrichedRisk,
};
};
20 changes: 17 additions & 3 deletions src/oneTrust/helpers/parseCliSyncOtArguments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,19 +47,33 @@ export const parseCliSyncOtArguments = (): OneTrustCliArguments => {
if (!dryRun && fileFormat !== OneTrustFileFormat.Csv) {
logger.error(
colors.red(
'Must not set the "fileFormat" parameter when "dryRun" is "false".',
`The "fileFormat" parameter must equal ${OneTrustFileFormat.Csv} when "dryRun" is "false".`,
),
);
}

if (!file) {
// If trying to sync to disk, must specify a file path
if (dryRun && !file) {
logger.error(
colors.red(
'Missing required parameter "file". e.g. --file=./oneTrustAssessments.json',
'Must set a "file" parameter when "dryRun" is "true". e.g. --file=./oneTrustAssessments.json',
),
);
return process.exit(1);
}

// If trying to sync to disk, must specify a file format
if (dryRun && !fileFormat) {
logger.error(
colors.red(
`Must set a "fileFormat" parameter when "dryRun" is "true". e.g. --fileFormat=${
OneTrustFileFormat.Json
}. Supported formats: ${VALID_FILE_FORMATS.join(',')}`,
),
);
return process.exit(1);
}

const splitFile = file.split('.');
if (splitFile.length < 2) {
logger.error(
Expand Down
94 changes: 94 additions & 0 deletions src/oneTrust/helpers/syncOneTrustAssessments.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { Got } from 'got/dist/source';
import {
getListOfOneTrustAssessments,
getOneTrustAssessment,
getOneTrustRisk,
} from '../endpoints';
import { map, mapSeries } from 'bluebird';
import { logger } from '../../logger';
import {
OneTrustAssessmentQuestion,
OneTrustAssessmentSection,
OneTrustGetRiskResponse,
} from '@transcend-io/privacy-types';
import uniq from 'lodash/uniq';
import { enrichOneTrustAssessment } from './enrichOneTrustAssessment';
import { writeOneTrustAssessment } from './writeOneTrustAssessment';
import { OneTrustFileFormat } from '../../enums';

export const syncOneTrustAssessments = async ({
oneTrust,
file,
fileFormat,
dryRun,
}: {
/** the OneTrust client instance */
oneTrust: Got;
/** Whether to write to file instead of syncing to Transcend */
dryRun: boolean;
/** the path to the file in case dryRun is true */
file?: string;
/** the format of the file in case dryRun is true */
fileFormat?: OneTrustFileFormat;
}): Promise<void> => {
// fetch the list of all assessments in the OneTrust organization
logger.info('Getting list of all assessments from OneTrust...');
const assessments = await getListOfOneTrustAssessments({ oneTrust });

/**
* fetch details about one assessment in series and push to transcend or write to disk
* (depending on the dryRun argument) right away to avoid running out of memory
*/
await mapSeries(assessments, async (assessment, index) => {
logger.info(
`Fetching details about assessment ${index + 1} of ${
assessments.length
}...`,
);
const assessmentDetails = await getOneTrustAssessment({
oneTrust,
assessmentId: assessment.assessmentId,
});

// enrich assessments with risk information
let riskDetails: OneTrustGetRiskResponse[] = [];
const riskIds = uniq(
assessmentDetails.sections.flatMap((s: OneTrustAssessmentSection) =>
s.questions.flatMap((q: OneTrustAssessmentQuestion) =>
(q.risks ?? []).flatMap((r) => r.riskId),
),
),
);
if (riskIds.length > 0) {
logger.info(
`Fetching details about ${riskIds.length} risks for assessment ${
index + 1
} of ${assessments.length}...`,
);
riskDetails = await map(
riskIds,
(riskId) => getOneTrustRisk({ oneTrust, riskId: riskId as string }),
{
concurrency: 5,
},
);
}

// enrich the sections with risk details
const enrichedAssessment = enrichOneTrustAssessment({
assessment,
assessmentDetails,
riskDetails,
});

if (dryRun && file && fileFormat) {
writeOneTrustAssessment({
assessment: enrichedAssessment,
index,
total: assessments.length,
file,
fileFormat,
});
}
});
};

0 comments on commit 13e80e9

Please sign in to comment.