Skip to content

Commit

Permalink
add support for syncing Assessments from OneTrust to Transcend (#376)
Browse files Browse the repository at this point in the history
* create flattenOneTrustAssessment helper

* flatten questionReponses

* create helper getOneTrustRisk

* update return type of getOneTrustRIsk

* convert OneTrust interfaces to codecs

* fix codecs

* fix codecs

* create flattenOneTrustSectionHeaders helper

* improve codecs and create flattenOneTrustQuestions helper

* improve variable names

* create extractProperties helper

* implement flattenOneTrustNestedQuestionsOptions

* improve flattenList

* improve flattenList

* update flattenOneTrustNestedQuestionsOptions to use aggregateObjects

* more changes

* update const flattenOneTrustSectionHeaders = (

* update const flattenOneTrustSectionHeaders = (

* commit

* commit

* create more helpers and add tests

* create enrichRiskStatisticsWithDefault

* fix bug

* remove extra test

* create more codecs

* flatten risks

* flatten approvers, respondents, and primaryEntityDetails

* update flattenOneTrustAssessment type

* create DEFAULT_ONE_TRUST_COMBINED_ASSESSMENT

* add comments

* update

* improve createDefatulCodec

* add missing fields to codec

* fix codecs

* undo changes to cli-pull-ot

* improve codecs

* done

* update writeOneTrustAssessment to write in csv format

* import assessment types from privacy types

* update type-utils

* remove enrich helpers

* import createDefaultCodec from type-utils

* rename cli-pull-ot -> cli-sync-ot

* add dryRun argument

* add dryRun argument

* move some logic from writeOneTrustAssessment to cli-sync-ot

* ship more improvements to writeOneTrustAssessment

* reorganize folder structure

* create syncOneTrustAssessments and enrichOneTrustAssessment helpers

* call syncOneTrustAssessments from cli-sync-ot

* create oneTrustAssessmentToJson helper

* create oneTrustAssessmentToCsv helper

* create oneTrustAssessmentToCsvRecord helper

* update readme

* move constants to heleprs

* add transcendUrl to the list of arguments

* add ability to sync to Transcend

* update error messages

* update extractProperties documentation

* add fixme comment

* write docs for aggregateObjects

* document  flattenObject

* remove some TODOs

* add TODOs

* remove TODOs

* add a fixme

* simplify flattenOneTrustAssessment

* improve flattenOneTrustSections

* improve flattenOneTrustSectionHeaders

* simplify flatten functions

* import aggregateObjects and flattenObject from @transcend/type-utils

* use transposeObjectArray from @transcend/type-utils

* improve flattenOneTrustAssessment

* update Readme

* update cli-sync-ot docs

* update package.version

* update commments

* remove potential bugs from flattenOneTrustAssessment

* add fixmes

* fix flattenOneTrustQuestionResponses

* fix flattenOneTrustNestedQuestionsOptions and add tests

* correctly flatten risks and add tests

* make progress in risk categories

* write more tests

* test flattenOneTrustSectionHeaders

* add flattenOneTrustSections tests

* default for pushing to transcend is json

* update enrichOneTrustAssessment to enrich creator

* create getOneTrustUser and cache fetched users

* remove FIXME

* enrich assessment with approver details

* enrich assessments with respondents information

* use privacy-types 4.105.3

* fix bugs and import codecs from privacy-types

* fix bug in syncONeTrustASsessmentToDisk

* rewrite syncOneTrustAssessments to run in parallel and series

* fix some bugs

* nits

* fix pre-commit

* fix tests
  • Loading branch information
abrantesarthur authored Jan 24, 2025
1 parent 801ba52 commit 925b974
Show file tree
Hide file tree
Showing 33 changed files with 2,036 additions and 743 deletions.
20 changes: 10 additions & 10 deletions .pnp.cjs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file not shown.
Binary file not shown.
53 changes: 40 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@
- [Authentication](#authentication-34)
- [Arguments](#arguments-33)
- [Usage](#usage-34)
- [tr-sync-ot](#tr-sync-ot)
- [tr-build-xdi-sync-endpoint](#tr-build-xdi-sync-endpoint)
- [Authentication](#authentication-35)
- [Arguments](#arguments-34)
Expand Down Expand Up @@ -176,7 +177,7 @@ yarn add -D @transcend-io/cli

# cli commands available within package
yarn tr-pull --auth=$TRANSCEND_API_KEY
yarn tr-pull-ot --auth=$ONE_TRUST_OAUTH_TOKEN --hostname=$ONE_TRUST_HOSTNAME --file=$ONE_TRUST_OUTPUT_FILE
yarn tr-sync-ot --auth=$ONE_TRUST_OAUTH_TOKEN --hostname=$ONE_TRUST_HOSTNAME --file=$ONE_TRUST_OUTPUT_FILE
yarn tr-push --auth=$TRANSCEND_API_KEY
yarn tr-scan-packages --auth=$TRANSCEND_API_KEY
yarn tr-discover-silos --auth=$TRANSCEND_API_KEY
Expand Down Expand Up @@ -217,7 +218,7 @@ npm i -D @transcend-io/cli

# cli commands available within package
tr-pull --auth=$TRANSCEND_API_KEY
tr-pull-ot --auth=$ONE_TRUST_OAUTH_TOKEN --hostname=$ONE_TRUST_HOSTNAME --file=$ONE_TRUST_OUTPUT_FILE
tr-sync-ot --auth=$ONE_TRUST_OAUTH_TOKEN --hostname=$ONE_TRUST_HOSTNAME --file=$ONE_TRUST_OUTPUT_FILE
tr-push --auth=$TRANSCEND_API_KEY
tr-scan-packages --auth=$TRANSCEND_API_KEY
tr-discover-silos --auth=$TRANSCEND_API_KEY
Expand Down Expand Up @@ -577,9 +578,9 @@ tr-pull --auth=./transcend-api-keys.json --resources=consentManager --file=./tra

Note: This command will overwrite the existing transcend.yml file that you have locally.

### tr-pull-ot
### tr-sync-ot

Pulls resources from a OneTrust instance. For now, it only supports retrieving OneTrust Assessments. It sends a request to the [Get List of Assessments](https://developer.onetrust.com/onetrust/reference/getallassessmentbasicdetailsusingget) endpoint to fetch a list of all Assessments in your account. Then, it queries the [Get Assessment](https://developer.onetrust.com/onetrust/reference/exportassessmentusingget) and [Get Risk](https://developer.onetrust.com/onetrust/reference/getriskusingget) endpoints to enrich these assessments with more details such as respondents, approvers, assessment questions and responses, and assessment risks. Finally, it syncs the enriched resources to disk in the specified file and format.
Pulls resources from a OneTrust and syncs them to a Transcend instance. For now, it only supports retrieving OneTrust Assessments. It sends a request to the [Get List of Assessments](https://developer.onetrust.com/onetrust/reference/getallassessmentbasicdetailsusingget) endpoint to fetch a list of all Assessments in your account. Then, it queries the [Get Assessment](https://developer.onetrust.com/onetrust/reference/exportassessmentusingget), [Get Risk](https://developer.onetrust.com/onetrust/reference/getriskusingget), and [Get User](https://developer.onetrust.com/onetrust/reference/getuserbyid) endpoints to enrich these assessments with more details such as respondents, approvers, assessment questions and responses, and assessment risks. Finally, it syncs the enriched resources to disk in the specified file and format.

This command can be helpful if you are looking to:

Expand All @@ -593,25 +594,51 @@ In order to use this command, you will need to generate a OneTrust OAuth Token w
- [GET /v2/assessments](https://developer.onetrust.com/onetrust/reference/getallassessmentbasicdetailsusingget)
- [GET /v2/assessments/{assessmentId}/export](https://developer.onetrust.com/onetrust/reference/exportassessmentusingget)
- [GET /risks/{riskId}](https://developer.onetrust.com/onetrust/reference/getriskusingget)
- [GET /v2/Users/{userId}](https://developer.onetrust.com/onetrust/reference/getuserusingget)

To learn how to generate the token, see the [OAuth 2.0 Scopes](https://developer.onetrust.com/onetrust/reference/oauth-20-scopes) and [Generate Access Token](https://developer.onetrust.com/onetrust/reference/getoauthtoken) pages.

If syncing the resources to Transcend, you will also need to generate an API key on the Transcend Admin Dashboard (https://app.transcend.io/infrastructure/api-keys).

The API key needs the following scopes when pushing the various resource types:

| Resource | Scope |
| ----------- | ------------------ |
| assessments | Manage Assessments |

#### Arguments

| Argument | Description | Type | Default | Required |
| ---------- | ------------------------------------------------------------------------------------------------- | ------- | ----------- | -------- |
| auth | The OAuth access token with the scopes necessary to access the OneTrust Public APIs. | string | N/A | true |
| hostname | The domain of the OneTrust environment from which to pull the resource (e.g. trial.onetrust.com). | string | N/A | true |
| file | Path to the file to pull the resource into. Its format must match the fileFormat argument. | string | N/A | true |
| fileFormat | The format of the output file. For now, only json is supported. | string | json | false |
| resource | The resource to pull from OneTrust. For now, only assessments is supported. | string | assessments | false |
| debug | Whether to print detailed logs in case of error. | boolean | false | false |
| Argument | Description | Type | Default | Required |
| ------------- | ------------------------------------------------------------------------------------------------- | ------------ | ------------------------ | -------- |
| hostname | The domain of the OneTrust environment from which to pull the resource (e.g. trial.onetrust.com). | string | N/A | true |
| oneTrustAuth | The OAuth access token with the scopes necessary to access the OneTrust Public APIs. | string | N/A | true |
| transcendAuth | The Transcend API Key to with the scopes necessary to access Transcend's Public APIs. | string | N/A | false |
| transcendUrl | URL of the Transcend backend. Use https://api.us.transcend.io for US hosting. | string - URL | https://api.transcend.io | false |
| file | Path to the file to pull the resource into. Its format must match the fileFormat argument. | string | N/A | false |
| fileFormat | The format of the output file. | string | json | false |
| resource | The resource to pull from OneTrust. For now, only assessments is supported. | string | assessments | false |
| dryRun | Whether to export the resource to a file rather than sync to Transcend. | boolean | false | false |
| debug | Whether to print detailed logs in case of error. | boolean | false | false |

#### Usage

```sh
# Syncs all assessments from the OneTrust instance to Transcend
tr-sync-ot --hostname=trial.onetrust.com --oneTrustAuth=$ONE_TRUST_OAUTH_TOKEN --transcendAuth=$TRANSCEND_API_KEY
```

Alternatively, you can set dryRun to true and sync the resource to disk:

```sh
# Writes out file to ./oneTrustAssessments.csv
tr-sync-ot --hostname=trial.onetrust.com --oneTrustAuth=$ONE_TRUST_OAUTH_TOKEN --dryRun=true --file=./oneTrustAssessments.csv
```

You can also sync to disk in json format:

```sh
# Writes out file to ./oneTrustAssessments.json
tr-pull-ot --auth=$ONE_TRUST_OAUTH_TOKEN --hostname=trial.onetrust.com --file=./oneTrustAssessments.json
tr-sync-ot --hostname=trial.onetrust.com --oneTrustAuth=$ONE_TRUST_OAUTH_TOKEN --dryRun=true --fileFormat=json --file=./oneTrustAssessments.json
```

### tr-push
Expand Down
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"author": "Transcend Inc.",
"name": "@transcend-io/cli",
"description": "Small package containing useful typescript utilities.",
"version": "6.13.2",
"version": "6.14.0",
"homepage": "https://github.com/transcend-io/cli",
"repository": {
"type": "git",
Expand All @@ -28,7 +28,6 @@
"tr-pull-consent-metrics": "./build/cli-pull-consent-metrics.js",
"tr-pull-consent-preferences": "./build/cli-pull-consent-preferences.js",
"tr-pull-datapoints": "./build/cli-pull-datapoints.js",
"tr-pull-ot": "./build/cli-pull-ot.js",
"tr-push": "./build/cli-push.js",
"tr-request-approve": "./build/cli-request-approve.js",
"tr-request-cancel": "./build/cli-request-cancel.js",
Expand All @@ -42,6 +41,7 @@
"tr-retry-request-data-silos": "./build/cli-retry-request-data-silos.js",
"tr-scan-packages": "./build/cli-scan-packages.js",
"tr-skip-request-data-silos": "./build/cli-skip-request-data-silos.js",
"tr-sync-ot": "./build/cli-sync-ot.js",
"tr-update-consent-manager": "./build/cli-update-consent-manager-to-latest.js",
"tr-upload-consent-preferences": "./build/cli-upload-consent-preferences.js",
"tr-upload-cookies-from-csv": "./build/cli-upload-cookies-from-csv.js",
Expand All @@ -68,9 +68,9 @@
"@transcend-io/handlebars-utils": "^1.1.0",
"@transcend-io/internationalization": "^1.6.0",
"@transcend-io/persisted-state": "^1.0.4",
"@transcend-io/privacy-types": "^4.103.0",
"@transcend-io/privacy-types": "^4.105.3",
"@transcend-io/secret-value": "^1.2.0",
"@transcend-io/type-utils": "^1.5.0",
"@transcend-io/type-utils": "^1.8.0",
"bluebird": "^3.7.2",
"cli-progress": "^3.11.2",
"colors": "^1.4.0",
Expand Down
76 changes: 0 additions & 76 deletions src/cli-pull-ot.ts

This file was deleted.

70 changes: 70 additions & 0 deletions src/cli-sync-ot.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/usr/bin/env node
import { logger } from './logger';

import colors from 'colors';
import { parseCliSyncOtArguments, createOneTrustGotInstance } from './oneTrust';
import { OneTrustPullResource } from './enums';
import { syncOneTrustAssessments } from './oneTrust/helpers/syncOneTrustAssessments';
import { buildTranscendGraphQLClient } from './graphql';

/**
* Pull configuration from OneTrust down locally to disk
*
* Dev Usage:
* yarn ts-node ./src/cli-sync-ot.ts --hostname=customer.my.onetrust.com --oneTrustAuth=$ONE_TRUST_OAUTH_TOKEN --transcendAuth=$TRANSCEND_API_KEY
*
* Standard usage
* yarn cli-sync-ot --hostname=customer.my.onetrust.com --oneTrustAuth=$ONE_TRUST_OAUTH_TOKEN --transcendAuth=$TRANSCEND_API_KEY
*/
async function main(): Promise<void> {
const {
file,
fileFormat,
hostname,
oneTrustAuth,
transcendAuth,
transcendUrl,
resource,
// debug,
dryRun,
} = parseCliSyncOtArguments();

// use the hostname and auth token to instantiate a client to talk to OneTrust
const oneTrust = createOneTrustGotInstance({ hostname, auth: oneTrustAuth });

// try {
if (resource === OneTrustPullResource.Assessments) {
await syncOneTrustAssessments({
oneTrust,
file,
fileFormat,
dryRun,
...(transcendAuth && transcendUrl
? {
transcend: buildTranscendGraphQLClient(transcendUrl, transcendAuth),
}
: {}),
});
}
// } catch (err) {
// logger.error(
// colors.red(
// `An error occurred syncing the resource ${resource} from OneTrust: ${
// debug ? err.stack : err.message
// }`,
// ),
// );
// process.exit(1);
// }

// Indicate success
logger.info(
colors.green(
`Successfully synced OneTrust ${resource} to ${
dryRun ? `disk at "${file}"` : 'Transcend'
}!`,
),
);
}

main();
30 changes: 30 additions & 0 deletions src/codecs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2073,3 +2073,33 @@ export const PathfinderPromptRunMetadata = t.partial({
export type PathfinderPromptRunMetadata = t.TypeOf<
typeof PathfinderPromptRunMetadata
>;

/** The columns of a row of a OneTrust Assessment form to import into Transcend. */
const OneTrustAssessmentColumnInput = t.intersection([
t.type({
/** The title of the column */
title: t.string,
}),
t.partial({
/** The optional value of the column */
value: t.string,
}),
]);

/** A row with information of the OneTrust assessment form to import into Transcend */
const OneTrustAssessmentRowInput = t.type({
/** A list of columns within this row. */
columns: t.array(OneTrustAssessmentColumnInput),
});

/** Input for importing multiple OneTrust assessment forms into Transcend */
export const ImportOnetrustAssessmentsInput = t.partial({
/** 'The rows of the CSV file.' */
rows: t.array(OneTrustAssessmentRowInput),
/** 'The json record representing the assessment.' */
json: t.string,
});
/** Type override */
export type ImportOnetrustAssessmentsInput = t.TypeOf<
typeof ImportOnetrustAssessmentsInput
>;
13 changes: 13 additions & 0 deletions src/graphql/gqls/assessment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,3 +283,16 @@ export const ASSESSMENTS = gql`
}
}
`;

export const IMPORT_ONE_TRUST_ASSESSMENT_FORMS = gql`
mutation TranscendCliImportOneTrustAssessmentForms(
$input: ImportOnetrustAssessmentsInput!
) {
importOneTrustAssessmentForms(input: $input) {
assessmentForms {
id
title
}
}
}
`;
Loading

0 comments on commit 925b974

Please sign in to comment.