Skip to content

Commit a719dca

Browse files
author
Rafael Murata
authored
Merge pull request #3 from rafaelMurata/finding-source-mute-samples
feat: Adding API v2 Source Finding Mute sample
2 parents 4057825 + 4a3ea21 commit a719dca

16 files changed

+816
-9
lines changed

security-center/snippets/system-test/v2/findings.test.js

+40-2
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,13 @@ const uuid = require('uuid');
2424
const organizationId = process.env['GCLOUD_ORGANIZATION'];
2525
const location = 'global';
2626

27-
describe('Client with SourcesAndFindings V2', async () => {
27+
describe('Client with sources and findings V2', async () => {
2828
let data;
2929
before(async () => {
3030
// Creates a new client.
3131
const client = new SecurityCenterClient();
32+
33+
const [projectId] = await client.getProjectId();
3234
const [source] = await client
3335
.createSource({
3436
source: {
@@ -62,16 +64,20 @@ describe('Client with SourcesAndFindings V2', async () => {
6264
},
6365
},
6466
};
67+
6568
const [finding] = await client.createFinding(createFindingTemplate);
6669
createFindingTemplate.findingId = 'untouchedFindingId';
6770
createFindingTemplate.finding.category = 'XSS';
6871
const [untouchedFinding] = await client
6972
.createFinding(createFindingTemplate)
7073
.catch(error => console.error(error));
74+
7175
data = {
7276
orgId: organizationId,
7377
sourceId: sourceId,
7478
sourceName: source.name,
79+
findingId: findingId,
80+
projectId: projectId,
7581
findingName: finding.name,
7682
untouchedFindingName: untouchedFinding.name,
7783
};
@@ -106,4 +112,36 @@ describe('Client with SourcesAndFindings V2', async () => {
106112
assert.notMatch(output, /undefined/);
107113
});
108114

109-
});
115+
it('client can mute a findings V2', () => {
116+
const output = exec(`node v2/setMuteFinding.js ${data.orgId} ${data.sourceId} ${data.findingId}`);
117+
assert.match(output, new RegExp('MUTED'));
118+
assert.match(output, /Mute value for the finding/);
119+
assert.notMatch(output, /undefined/);
120+
});
121+
122+
it('client can un mute a findings V2', () => {
123+
const output = exec(`node v2/setUnmuteFinding.js ${data.orgId} ${data.sourceId} ${data.findingId}`);
124+
assert.match(output, new RegExp('UNMUTED'));
125+
assert.match(output, /Unmute a finding/);
126+
assert.notMatch(output, /undefined/);
127+
});
128+
129+
it('client can group all findings V2', () => {
130+
const output = exec(`node v2/groupFindings.js ${data.orgId} ${data.sourceId}`);
131+
assert.isAtLeast(4, output.match(/\n/g).length + 1);
132+
assert.notMatch(output, /undefined/);
133+
});
134+
135+
it('client group filtered findings V2', () => {
136+
const output = exec(`node v2/groupFindingsWithFilter.js ${data.orgId} ${data.sourceId}`);
137+
assert.isAtLeast(4, output.match(/\n/g).length + 1);
138+
assert.notMatch(output, /undefined/);
139+
});
140+
141+
it('client can bulk a mute a findings V2', () => {
142+
const output = exec(`node v2/bulkMuteFindings.js ${data.orgId} ${data.projectId}`);
143+
assert.match(output, /Bulk mute findings completed successfully/);
144+
assert.notMatch(output, /undefined/);
145+
});
146+
147+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
* Copyright 2024 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
const { SecurityCenterClient } = require('@google-cloud/security-center').v2;
18+
const { assert } = require('chai');
19+
const { execSync } = require('child_process');
20+
const exec = cmd => execSync(cmd, { encoding: 'utf8' });
21+
const { describe, it, before } = require('mocha');
22+
const uuidv1 = require('uuid').v1;
23+
24+
const organizationId = process.env['GCLOUD_ORGANIZATION'];
25+
const location = 'global';
26+
27+
describe('Client with mute rule V2', async () => {
28+
let data;
29+
before(async () => {
30+
// Creates a new client.
31+
const client = new SecurityCenterClient();
32+
33+
// Build the create mute rule request.
34+
const muteId = 'muteid-'+uuidv1().replace(/-/g, '').substring(0, 20);
35+
const createMuteRuleRequest = {
36+
parent:`organizations/${organizationId}/locations/${location}`,
37+
muteConfigId:muteId,
38+
muteConfig:{
39+
name:`organizations/${organizationId}/locations/${location}/muteConfigs/${muteId}`,
40+
description: "Mute low-medium IAM grants excluding 'compute' resources",
41+
filter:
42+
"severity=\"LOW\" OR severity=\"MEDIUM\" AND " +
43+
"category=\"Persistence: IAM Anomalous Grant\" AND " +
44+
"-resource.type:\"compute\"",
45+
type: "STATIC",
46+
},
47+
};
48+
49+
const [muteConfigResponse] = await client
50+
.createMuteConfig(createMuteRuleRequest)
51+
.catch(error => console.error(error));
52+
53+
const muteConfigId = muteConfigResponse.name.split('/')[5];
54+
55+
data = {
56+
orgId: organizationId,
57+
muteConfigId: muteConfigId,
58+
muteConfigName: muteConfigResponse.name,
59+
untouchedMuteConfigName: "",
60+
};
61+
console.log('my data %j', data);
62+
});
63+
64+
after(async () => {
65+
const client = new SecurityCenterClient();
66+
67+
const name = `organizations/${organizationId}/locations/${location}/muteConfigs/${data.muteConfigId}`;
68+
await client.deleteMuteConfig({name: name}).catch(error => console.error(error));
69+
});
70+
71+
it('client can create mute rule V2', () => {
72+
const output = exec(`node v2/createMuteRule.js ${data.orgId}`);
73+
assert.match(output, new RegExp(data.orgId));
74+
assert.match(output, /New mute rule config created/);
75+
assert.notMatch(output, /undefined/);
76+
});
77+
78+
it('client can list all mute rules V2', () => {
79+
const output = exec(`node v2/listAllMuteRules.js ${data.orgId}`);
80+
assert.match(output, new RegExp(data.orgId));
81+
assert.match(output, new RegExp(data.untouchedMuteConfigName));
82+
assert.notMatch(output, /undefined/);
83+
});
84+
85+
it('client can get a mute rule V2', () => {
86+
const output = exec(`node v2/getMuteRule.js ${data.orgId} ${data.muteConfigId}`);
87+
assert.match(output, new RegExp(data.muteConfigName));
88+
assert.match(output, /Get mute rule config/);
89+
assert.notMatch(output, /undefined/);
90+
});
91+
92+
it('client can update a mute rule V2', () => {
93+
const output = exec(`node v2/updateMuteRule.js ${data.orgId} ${data.muteConfigId}`);
94+
assert.match(output, /Update mute rule config/);
95+
assert.notMatch(output, /undefined/);
96+
});
97+
98+
it('client can delete a mute rule V2', () => {
99+
const output = exec(`node v2/deleteMuteRule.js ${data.orgId} ${data.muteConfigId}`);
100+
assert.match(output, /Delete mute rule config/);
101+
assert.notMatch(output, /undefined/);
102+
});
103+
104+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright 2024 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
'use strict';
17+
18+
/**
19+
* Kicks off a long-running operation (LRO) to bulk mute findings for a parent based on a filter.
20+
* The parent can be either an organization, folder, or project. The findings
21+
* matched by the filter will be muted after the LRO is done.
22+
*/
23+
function main(organizationId, projectId, location = 'global') {
24+
// [START securitycenter_bulk_mute_v2]
25+
// Imports the Google Cloud client library.
26+
const { SecurityCenterClient } = require('@google-cloud/security-center').v2;
27+
28+
// Create a Security Center client
29+
const client = new SecurityCenterClient();
30+
31+
/**
32+
* Required. The parent, at which bulk action needs to be applied. If no
33+
* location is specified, findings are updated in global. The following list
34+
* shows some examples:
35+
* `organizations/[organization_id]`
36+
* `organizations/[organization_id]/locations/[location_id]`
37+
* `folders/[folder_id]`
38+
* `folders/[folder_id]/locations/[location_id]`
39+
* `projects/[project_id]`
40+
* `projects/[project_id]/locations/[location_id]`
41+
*/
42+
const parent = `organizations/${organizationId}/locations/${location}`;
43+
44+
// muteRule: Expression that identifies findings that should be muted.
45+
// Can also refer to an organization/ folder.
46+
// eg: "resource.project_display_name=\"PROJECT_ID\""
47+
const filter = `resource.project_display_name="${projectId}"`;
48+
49+
// Build the request.
50+
const bulkMuteFindingRequest = {
51+
parent,
52+
filter
53+
};
54+
55+
async function callBulkMuteFindings() {
56+
57+
// Call the API.
58+
const [operation] = await client.bulkMuteFindings(bulkMuteFindingRequest);
59+
const [response] = await operation.promise();
60+
console.log('Bulk mute findings completed successfully: %j', response);
61+
}
62+
63+
callBulkMuteFindings();
64+
// [END securitycenter_bulk_mute_v2]
65+
}
66+
67+
main(...process.argv.slice(2));

security-center/snippets/v2/createFinding.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -82,5 +82,4 @@ function main(organizationId, sourceId, location = 'global', category = 'LOW_RIS
8282
// [END securitycenter_create_finding_v2]
8383
}
8484

85-
main(...process.argv.slice(2));
86-
85+
main(...process.argv.slice(2));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright 2024 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
'use strict';
17+
18+
/**
19+
* Creates a mute configuration in a project under a given location.
20+
*/
21+
function main(organizationId, location = 'global') {
22+
// [START securitycenter_create_mute_config_v2]
23+
// Imports the Google Cloud client library.
24+
const { SecurityCenterClient } = require('@google-cloud/security-center').v2;
25+
const uuidv1 = require('uuid').v1;
26+
27+
// Create a Security Center client
28+
const client = new SecurityCenterClient();
29+
30+
/**
31+
* Required. Resource name of the new mute configs's parent. Its format is
32+
* "organizations/[organization_id]/locations/[location_id]",
33+
* "folders/[folder_id]/locations/[location_id]", or
34+
* "projects/[project_id]/locations/[location_id]".
35+
*/
36+
const parent = `organizations/${organizationId}/locations/${location}`;
37+
38+
/**
39+
* Required. Unique identifier provided by the client within the parent scope.
40+
* It must consist of only lowercase letters, numbers, and hyphens, must start
41+
* with a letter, must end with either a letter or a number, and must be 63
42+
* characters or less.
43+
*/
44+
const muteConfigId = 'muteid-'+uuidv1().replace(/-/g, '').substring(0, 20);
45+
46+
const name = `${parent}/muteConfigs/${muteConfigId}`;
47+
48+
// Build the muteRuleConfig object.
49+
const muteConfig = {
50+
name:name,
51+
description: "Mute low-medium IAM grants excluding 'compute' resources",
52+
filter:
53+
"severity=\"LOW\" OR severity=\"MEDIUM\" AND " +
54+
"category=\"Persistence: IAM Anomalous Grant\" AND " +
55+
"-resource.type:\"compute\"",
56+
type: "STATIC",
57+
};
58+
59+
// Build the create mute rule request.
60+
const createMuteRuleRequest = {
61+
parent,
62+
muteConfig,
63+
muteConfigId,
64+
};
65+
66+
async function createMuteRuleConfig() {
67+
68+
// Call the API.
69+
const [muteConfig] = await client.createMuteConfig(createMuteRuleRequest);
70+
console.log('New mute rule config created: %j', muteConfig);
71+
}
72+
73+
createMuteRuleConfig();
74+
// [END securitycenter_create_mute_config_v2]
75+
}
76+
77+
main(...process.argv.slice(2));

security-center/snippets/v2/createSource.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ function main(organizationId) {
5454
}
5555

5656
createSource();
57-
// [END securitycenter_create_source]
57+
// [END securitycenter_create_source_v2]
5858
}
5959

60-
main(...process.argv.slice(2));
60+
main(...process.argv.slice(2));

0 commit comments

Comments
 (0)