Skip to content

Commit fd1600d

Browse files
authored
Merge pull request #3035 from GoogleCloudPlatform/nodejs-dlp-migration
samples: migrate code from googleapis/nodejs-dlp
2 parents 792a62a + 2fb1355 commit fd1600d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+4284
-0
lines changed

.github/workflows/dlp.yaml

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# Copyright 2023 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
name: dlp
16+
on:
17+
push:
18+
branches:
19+
- main
20+
paths:
21+
- 'dlp/**'
22+
- '.github/workflows/dlp.yaml'
23+
pull_request:
24+
paths:
25+
- 'dlp/**'
26+
- '.github/workflows/dlp.yaml'
27+
pull_request_target:
28+
types: [labeled]
29+
paths:
30+
- 'dlp/**'
31+
- '.github/workflows/dlp.yaml'
32+
schedule:
33+
- cron: '0 0 * * 0'
34+
jobs:
35+
test:
36+
if: ${{ github.event.action != 'labeled' || github.event.label.name == 'actions:force-run' }}
37+
runs-on: ubuntu-latest
38+
timeout-minutes: 60
39+
permissions:
40+
contents: 'write'
41+
pull-requests: 'write'
42+
id-token: 'write'
43+
steps:
44+
- uses: actions/[email protected]
45+
with:
46+
ref: ${{github.event.pull_request.head.sha}}
47+
- uses: 'google-github-actions/[email protected]'
48+
with:
49+
workload_identity_provider: 'projects/1046198160504/locations/global/workloadIdentityPools/github-actions-pool/providers/github-actions-provider'
50+
service_account: '[email protected]'
51+
create_credentials_file: 'true'
52+
access_token_lifetime: 600s
53+
- uses: actions/[email protected]
54+
with:
55+
node-version: 16
56+
- run: npm install
57+
working-directory: dlp
58+
- run: npm test
59+
working-directory: dlp
60+
env:
61+
MOCHA_REPORTER_SUITENAME: dlp
62+
MOCHA_REPORTER_OUTPUT: dlp_sponge_log.xml
63+
MOCHA_REPORTER: xunit
64+
- if: ${{ github.event.action == 'labeled' && github.event.label.name == 'actions:force-run' }}
65+
uses: actions/github-script@v6
66+
with:
67+
github-token: ${{ secrets.GITHUB_TOKEN }}
68+
script: |
69+
try {
70+
await github.rest.issues.removeLabel({
71+
name: 'actions:force-run',
72+
owner: 'GoogleCloudPlatform',
73+
repo: 'nodejs-docs-samples',
74+
issue_number: context.payload.pull_request.number
75+
});
76+
} catch (e) {
77+
if (!e.message.includes('Label does not exist')) {
78+
throw e;
79+
}
80+
}
81+
- if: ${{ github.event_name == 'schedule' && always() }}
82+
run: |
83+
curl https://github.com/googleapis/repo-automation-bots/releases/download/flakybot-1.1.0/flakybot -o flakybot -s -L
84+
chmod +x ./flakybot
85+
./flakybot --repo GoogleCloudPlatform/nodejs-docs-samples --commit_hash ${{github.sha}} --build_url https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}

.github/workflows/workflows.json

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
"datastore/functions",
4343
"dialogflow",
4444
"dialogflow-cx",
45+
"dlp",
4546
"document-ai",
4647
"endpoints/getting-started",
4748
"endpoints/getting-started-grpc",

CODEOWNERS

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ secret-manager @GoogleCloudPlatform/dee-infra @GoogleCloudPlatform/nodejs-sample
3333
security-center @GoogleCloudPlatform/dee-infra @GoogleCloudPlatform/nodejs-samples-reviewers
3434
service-directory @GoogleCloudPlatform/dee-infra @GoogleCloudPlatform/nodejs-samples-reviewers
3535
webrisk @GoogleCloudPlatform/dee-infra @GoogleCloudPlatform/nodejs-samples-reviewers
36+
dlp @GoogleCloudPlatform/dee-infra @GoogleCloudPlatform/nodejs-samples-reviewers
3637

3738
# DEE Platform Ops (DEEPO)
3839
container @GoogleCloudPlatform/dee-platform-ops @GoogleCloudPlatform/nodejs-samples-reviewers

dlp/.eslintrc.yml

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
rules:
3+
no-console: off
4+
no-warning-comments: off
5+
node/no-missing-require: off

dlp/.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Test outputs
2+
*.actual.png
3+
*.actual.csv

dlp/categoricalRiskAnalysis.js

+160
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
// Copyright 2020 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
'use strict';
16+
17+
// sample-metadata:
18+
// title: Categorical Risk Analysis
19+
// description: Computes risk metrics of a column of data in a Google BigQuery table.
20+
// usage: node categoricalRiskAnalysis.js my-project nhtsa_traffic_fatalities accident_2015 state_name my-topic my-subscription bigquery-public-data
21+
22+
function main(
23+
projectId,
24+
tableProjectId,
25+
datasetId,
26+
tableId,
27+
columnName,
28+
topicId,
29+
subscriptionId
30+
) {
31+
// [START dlp_categorical_stats]
32+
// Import the Google Cloud client libraries
33+
const DLP = require('@google-cloud/dlp');
34+
const {PubSub} = require('@google-cloud/pubsub');
35+
36+
// Instantiates clients
37+
const dlp = new DLP.DlpServiceClient();
38+
const pubsub = new PubSub();
39+
40+
// The project ID to run the API call under
41+
// const projectId = 'my-project';
42+
43+
// The project ID the table is stored under
44+
// This may or (for public datasets) may not equal the calling project ID
45+
// const tableProjectId = 'my-project';
46+
47+
// The ID of the dataset to inspect, e.g. 'my_dataset'
48+
// const datasetId = 'my_dataset';
49+
50+
// The ID of the table to inspect, e.g. 'my_table'
51+
// const tableId = 'my_table';
52+
53+
// The name of the Pub/Sub topic to notify once the job completes
54+
// TODO(developer): create a Pub/Sub topic to use for this
55+
// const topicId = 'MY-PUBSUB-TOPIC'
56+
57+
// The name of the Pub/Sub subscription to use when listening for job
58+
// completion notifications
59+
// TODO(developer): create a Pub/Sub subscription to use for this
60+
// const subscriptionId = 'MY-PUBSUB-SUBSCRIPTION'
61+
62+
// The name of the column to compute risk metrics for, e.g. 'firstName'
63+
// const columnName = 'firstName';
64+
async function categoricalRiskAnalysis() {
65+
const sourceTable = {
66+
projectId: tableProjectId,
67+
datasetId: datasetId,
68+
tableId: tableId,
69+
};
70+
71+
// Construct request for creating a risk analysis job
72+
const request = {
73+
parent: `projects/${projectId}/locations/global`,
74+
riskJob: {
75+
privacyMetric: {
76+
categoricalStatsConfig: {
77+
field: {
78+
name: columnName,
79+
},
80+
},
81+
},
82+
sourceTable: sourceTable,
83+
actions: [
84+
{
85+
pubSub: {
86+
topic: `projects/${projectId}/topics/${topicId}`,
87+
},
88+
},
89+
],
90+
},
91+
};
92+
93+
// Create helper function for unpacking values
94+
const getValue = obj => obj[Object.keys(obj)[0]];
95+
96+
// Run risk analysis job
97+
const [topicResponse] = await pubsub.topic(topicId).get();
98+
const subscription = await topicResponse.subscription(subscriptionId);
99+
const [jobsResponse] = await dlp.createDlpJob(request);
100+
const jobName = jobsResponse.name;
101+
// Watch the Pub/Sub topic until the DLP job finishes
102+
await new Promise((resolve, reject) => {
103+
const messageHandler = message => {
104+
if (message.attributes && message.attributes.DlpJobName === jobName) {
105+
message.ack();
106+
subscription.removeListener('message', messageHandler);
107+
subscription.removeListener('error', errorHandler);
108+
resolve(jobName);
109+
} else {
110+
message.nack();
111+
}
112+
};
113+
114+
const errorHandler = err => {
115+
subscription.removeListener('message', messageHandler);
116+
subscription.removeListener('error', errorHandler);
117+
reject(err);
118+
};
119+
120+
subscription.on('message', messageHandler);
121+
subscription.on('error', errorHandler);
122+
});
123+
setTimeout(() => {
124+
console.log(' Waiting for DLP job to fully complete');
125+
}, 500);
126+
const [job] = await dlp.getDlpJob({name: jobName});
127+
const histogramBuckets =
128+
job.riskDetails.categoricalStatsResult.valueFrequencyHistogramBuckets;
129+
histogramBuckets.forEach((histogramBucket, histogramBucketIdx) => {
130+
console.log(`Bucket ${histogramBucketIdx}:`);
131+
132+
// Print bucket stats
133+
console.log(
134+
` Most common value occurs ${histogramBucket.valueFrequencyUpperBound} time(s)`
135+
);
136+
console.log(
137+
` Least common value occurs ${histogramBucket.valueFrequencyLowerBound} time(s)`
138+
);
139+
140+
// Print bucket values
141+
console.log(`${histogramBucket.bucketSize} unique values total.`);
142+
histogramBucket.bucketValues.forEach(valueBucket => {
143+
console.log(
144+
` Value ${getValue(valueBucket.value)} occurs ${
145+
valueBucket.count
146+
} time(s).`
147+
);
148+
});
149+
});
150+
}
151+
152+
categoricalRiskAnalysis();
153+
// [END dlp_categorical_stats]
154+
}
155+
156+
main(...process.argv.slice(2));
157+
process.on('unhandledRejection', err => {
158+
console.error(err.message);
159+
process.exitCode = 1;
160+
});

dlp/createInspectTemplate.js

+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
// Copyright 2020 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
'use strict';
16+
17+
// sample-metadata:
18+
// title: Inspect Templates
19+
// description: Create a new DLP inspection configuration template.
20+
// usage: node createInspectTemplate.js my-project VERY_LIKELY PERSON_NAME 5 false my-template-id
21+
22+
function main(
23+
projectId,
24+
templateId,
25+
displayName,
26+
infoTypes,
27+
includeQuote,
28+
minLikelihood,
29+
maxFindings
30+
) {
31+
infoTypes = transformCLI(infoTypes);
32+
// [START dlp_create_inspect_template]
33+
// Imports the Google Cloud Data Loss Prevention library
34+
const DLP = require('@google-cloud/dlp');
35+
36+
// Instantiates a client
37+
const dlp = new DLP.DlpServiceClient();
38+
39+
// The project ID to run the API call under
40+
// const projectId = 'my-project';
41+
42+
// The minimum likelihood required before returning a match
43+
// const minLikelihood = 'LIKELIHOOD_UNSPECIFIED';
44+
45+
// The maximum number of findings to report per request (0 = server maximum)
46+
// const maxFindings = 0;
47+
48+
// The infoTypes of information to match
49+
// const infoTypes = [{ name: 'PHONE_NUMBER' }, { name: 'EMAIL_ADDRESS' }, { name: 'CREDIT_CARD_NUMBER' }];
50+
51+
// Whether to include the matching string
52+
// const includeQuote = true;
53+
54+
// (Optional) The name of the template to be created.
55+
// const templateId = 'my-template';
56+
57+
// (Optional) The human-readable name to give the template
58+
// const displayName = 'My template';
59+
60+
async function createInspectTemplate() {
61+
// Construct the inspection configuration for the template
62+
const inspectConfig = {
63+
infoTypes: infoTypes,
64+
minLikelihood: minLikelihood,
65+
includeQuote: includeQuote,
66+
limits: {
67+
maxFindingsPerRequest: maxFindings,
68+
},
69+
};
70+
71+
// Construct template-creation request
72+
const request = {
73+
parent: `projects/${projectId}/locations/global`,
74+
inspectTemplate: {
75+
inspectConfig: inspectConfig,
76+
displayName: displayName,
77+
},
78+
templateId: templateId,
79+
};
80+
81+
const [response] = await dlp.createInspectTemplate(request);
82+
const templateName = response.name;
83+
console.log(`Successfully created template ${templateName}.`);
84+
}
85+
createInspectTemplate();
86+
// [END dlp_create_inspect_template]
87+
}
88+
89+
main(...process.argv.slice(2));
90+
process.on('unhandledRejection', err => {
91+
console.error(err.message);
92+
process.exitCode = 1;
93+
});
94+
95+
function transformCLI(infoTypes) {
96+
infoTypes = infoTypes
97+
? infoTypes.split(',').map(type => {
98+
return {name: type};
99+
})
100+
: undefined;
101+
return infoTypes;
102+
}

0 commit comments

Comments
 (0)