Skip to content

Commit

Permalink
Merge branch 'main' into renovate/c8-8.x
Browse files Browse the repository at this point in the history
  • Loading branch information
pattishin committed Jun 21, 2023
2 parents bd225ec + 76c51f0 commit 7a58084
Show file tree
Hide file tree
Showing 4 changed files with 253 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"url": "https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git"
},
"engines": {
"node": "=v16.20.0"
"node": "=v16.20.1"
},
"scripts": {
"start": "node app.js",
Expand Down
132 changes: 132 additions & 0 deletions dlp/deIdentifyTableWithFpe.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

'use strict';

// sample-metadata:
// title: De-identify with FPE
// description: De-identify sensitive data in a string using Format Preserving Encryption (FPE).
// usage: node deIdentifyTableWithFpe.js my-project alphabet keyName wrappedKey
async function main(projectId, alphabet, keyName, wrappedKey) {
// [START dlp_deidentify_table_fpe]
// Imports the Google Cloud Data Loss Prevention library
const DLP = require('@google-cloud/dlp');

// Instantiates a client
const dlp = new DLP.DlpServiceClient();

// The project ID to run the API call under
// const projectId = 'my-project';

// The set of characters to replace sensitive ones with
// For more information, see https://cloud.google.com/dlp/docs/reference/rest/v2/organizations.deidentifyTemplates#ffxcommonnativealphabet
// const alphabet = 'NUMERIC';

// The name of the Cloud KMS key used to encrypt ('wrap') the AES-256 key
// const keyName = 'projects/YOUR_GCLOUD_PROJECT/locations/YOUR_LOCATION/keyRings/YOUR_KEYRING_NAME/cryptoKeys/YOUR_KEY_NAME';

// The encrypted ('wrapped') AES-256 key to use
// This key should be encrypted using the Cloud KMS key specified above
// const wrappedKey = 'YOUR_ENCRYPTED_AES_256_KEY'

// Table to de-identify
const tablularData = {
headers: [{name: 'Employee ID'}, {name: 'Date'}, {name: 'Compensation'}],
rows: [
{
values: [
{stringValue: '11111'},
{stringValue: '2015'},
{stringValue: '$10'},
],
},
{
values: [
{stringValue: '22222'},
{stringValue: '2016'},
{stringValue: '$20'},
],
},
{
values: [
{stringValue: '33333'},
{stringValue: '2016'},
{stringValue: '$15'},
],
},
],
};

async function deidentifyTableWithFpe() {
// Specify field to be encrypted.
const fieldIds = [{name: 'Employee ID'}];

// Specify an encrypted AES-256 key and the name of the Cloud KMS key that encrypted it
const cryptoKeyConfig = {
kmsWrapped: {
wrappedKey: wrappedKey,
cryptoKeyName: keyName,
},
};

// Specify how the content should be encrypted.
const cryptoReplaceFfxFpeConfig = {
cryptoKey: cryptoKeyConfig,
commonAlphabet: alphabet,
};

// Associate the encryption with the specified field.
const fieldTransformations = [
{
fields: fieldIds,
primitiveTransformation: {
cryptoReplaceFfxFpeConfig,
},
},
];

// Combine configurations into a request for the service.
const request = {
parent: `projects/${projectId}/locations/global`,
deidentifyConfig: {
recordTransformations: {
fieldTransformations,
},
},
item: {
table: tablularData,
},
};

// Send the request and receive response from the service.
const [response] = await dlp.deidentifyContent(request);

// Print the results.
console.log(
`Table after de-identification: ${JSON.stringify(response.item.table)}`
);
}
await deidentifyTableWithFpe();
// [END dlp_deidentify_table_fpe]
}

process.on('unhandledRejection', err => {
console.error(err.message);
process.exitCode = 1;
});

// TODO(developer): Please uncomment below line before running sample
// main(...process.argv.slice(2));

module.exports = main;
62 changes: 62 additions & 0 deletions dlp/system-test/deid.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ const {describe, it, before} = require('mocha');
const fs = require('fs');
const cp = require('child_process');
const DLP = require('@google-cloud/dlp');
const proxyquire = require('proxyquire');
const sinon = require('sinon');
const {MOCK_DATA} = require('./mockdata');

const execSync = cmd => cp.execSync(cmd, {encoding: 'utf-8'});

Expand All @@ -30,6 +33,8 @@ const csvFile = 'resources/dates.csv';
const tempOutputFile = path.join(__dirname, 'temp.result.csv');
const dateShiftAmount = 30;
const dateFields = 'birth_date,register_date';
const keyName = 'KEY_NAME';
const wrappedKey = 'WRAPPED_KEY';

const client = new DLP.DlpServiceClient();
describe('deid', () => {
Expand All @@ -38,6 +43,11 @@ describe('deid', () => {
before(async () => {
projectId = await client.getProjectId();
});

afterEach(async () => {
sinon.restore();
});

// deidentify_masking
it('should mask sensitive data in a string', () => {
const output = execSync(
Expand Down Expand Up @@ -357,4 +367,56 @@ describe('deid', () => {
}
assert.include(output, 'INVALID_ARGUMENT');
});

// dlp_deidentify_table_fpe
it('should de-identify table using Format Preserving Encryption (FPE)', async () => {
const CONSTANT_DATA = MOCK_DATA.DEIDENTIFY_TABLE_WITH_FPE(
projectId,
'NUMERIC',
keyName,
wrappedKey
);

const mockDeidentifyContent = sinon
.stub()
.resolves(CONSTANT_DATA.RESPONSE_DEIDENTIFY_CONTENT);

sinon.replace(
DLP.DlpServiceClient.prototype,
'deidentifyContent',
mockDeidentifyContent
);
sinon.replace(console, 'log', () => sinon.stub());

const deIdentifyTableWithFpe = proxyquire('../deIdentifyTableWithFpe', {
'@google-cloud/dlp': {DLP: DLP},
});

await deIdentifyTableWithFpe(projectId, 'NUMERIC', keyName, wrappedKey);

sinon.assert.calledOnceWithExactly(
mockDeidentifyContent,
CONSTANT_DATA.REQUEST_DEIDENTIFY_CONTENT
);
});

it('should handle de-identification errors', async () => {
const mockDeidentifyContent = sinon.stub().rejects(new Error('Failed'));
sinon.replace(
DLP.DlpServiceClient.prototype,
'deidentifyContent',
mockDeidentifyContent
);
sinon.replace(console, 'log', () => sinon.stub());

const deIdentifyTableWithFpe = proxyquire('../deIdentifyTableWithFpe', {
'@google-cloud/dlp': {DLP: DLP},
});

try {
await deIdentifyTableWithFpe(projectId, 'NUMERIC', keyName, wrappedKey);
} catch (error) {
assert.equal(error.message, 'Failed');
}
});
});
58 changes: 58 additions & 0 deletions dlp/system-test/mockdata.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,64 @@ const MOCK_DATA = {
nack: sinon.stub(),
},
}),
DEIDENTIFY_TABLE_WITH_FPE: (projectId, alphabet, keyName, wrappedKey) => ({
REQUEST_DEIDENTIFY_CONTENT: {
parent: `projects/${projectId}/locations/global`,
deidentifyConfig: {
recordTransformations: {
fieldTransformations: [
{
fields: [{name: 'Employee ID'}],
primitiveTransformation: {
cryptoReplaceFfxFpeConfig: {
cryptoKey: {
kmsWrapped: {
wrappedKey: wrappedKey,
cryptoKeyName: keyName,
},
},
commonAlphabet: alphabet,
},
},
},
],
},
},
item: {
table: {
headers: [
{name: 'Employee ID'},
{name: 'Date'},
{name: 'Compensation'},
],
rows: [
{
values: [
{stringValue: '11111'},
{stringValue: '2015'},
{stringValue: '$10'},
],
},
{
values: [
{stringValue: '22222'},
{stringValue: '2016'},
{stringValue: '$20'},
],
},
{
values: [
{stringValue: '33333'},
{stringValue: '2016'},
{stringValue: '$15'},
],
},
],
},
},
},
RESPONSE_DEIDENTIFY_CONTENT: [{item: {table: {}}}],
}),
};

module.exports = {MOCK_DATA};

0 comments on commit 7a58084

Please sign in to comment.