diff --git a/security-center/snippets/system-test/v1/notifications.test.js b/security-center/snippets/system-test/v1/notifications.test.js index d20e6d0371..afe48660da 100644 --- a/security-center/snippets/system-test/v1/notifications.test.js +++ b/security-center/snippets/system-test/v1/notifications.test.js @@ -26,6 +26,30 @@ const organizationId = '1081635000895'; const orgName = 'organizations/' + organizationId; const pubsubTopic = 'projects/project-a-id/topics/notifications-sample-topic'; +async function waitForConfig(client, configId) { + const maxRetries = 10; + const retryDelay = 1000; // 1 second + let retries = 0; + + while (retries < maxRetries) { + try { + const name = client.organizationNotificationConfigPath( + organizationId, + configId + ); + const [config] = await client.getNotificationConfig({name}); + if (config) return; + } catch (err) { + // Ignore "not found" errors + if (err.code !== 404) throw err; + } + retries++; + await new Promise(resolve => setTimeout(resolve, retryDelay)); + } + + throw new Error(`Timeout waiting for config ${configId} to be available`); +} + describe('Client with Notifications', async () => { const createConfig = 'notif-config-test-node-create' + uuidv1(); const deleteConfig = 'notif-config-test-node-delete' + uuidv1(); @@ -36,38 +60,80 @@ describe('Client with Notifications', async () => { before(async () => { const client = new SecurityCenterClient(); async function createNotificationConfig(configId) { - /*eslint no-unused-vars: ["error", { "varsIgnorePattern": "^_" }]*/ - const [_response] = await client.createNotificationConfig({ - parent: orgName, - configId: configId, - notificationConfig: { - description: 'Sample config for node.js', - pubsubTopic: pubsubTopic, - streamingConfig: {filter: 'state = "ACTIVE"'}, - }, - }); + try { + /*eslint no-unused-vars: ["error", { "varsIgnorePattern": "^_" }]*/ + const [_response] = await client.createNotificationConfig({ + parent: orgName, + configId: configId, + notificationConfig: { + description: 'Sample config for node.js', + pubsubTopic: pubsubTopic, + streamingConfig: {filter: 'state = "ACTIVE"'}, + }, + }); + } catch (err) { + if (err.code === 400) { + console.error(`Invalid input for config ${configId}:`, err.message); + } else if (err.code === 503) { + console.error( + `Service unavailable when creating config ${configId}:`, + err.message + ); + } else { + console.error( + `Unexpected error creating config ${configId}:`, + err.message + ); + } + } } await createNotificationConfig(deleteConfig); + await waitForConfig(client, deleteConfig); await createNotificationConfig(getConfig); + await waitForConfig(client, getConfig); await createNotificationConfig(listConfig); + await waitForConfig(client, listConfig); await createNotificationConfig(updateConfig); + await waitForConfig(client, updateConfig); }); after(async () => { const client = new SecurityCenterClient(); - async function deleteNotificationConfig(configId) { + async function deleteNotificationConfigIfExists(configId) { const name = client.organizationNotificationConfigPath( organizationId, configId ); - await client.deleteNotificationConfig({name: name}); + try { + // Check if the config exists + const [config] = await client.getNotificationConfig({name}); + if (config) { + // Proceed with deletion if the config exists + await client.deleteNotificationConfig({name: name}); + console.log(`Config ${configId} deleted successfully.`); + } + } catch (err) { + if (err.code === 404) { + console.warn(`Config ${configId} not found during deletion.`); + } else if (err.code === 503) { + console.error( + `Service unavailable when deleting config ${configId}:`, + err.message + ); + } else { + console.error( + `Unexpected error deleting config ${configId}:`, + err.message + ); + } + } } - await deleteNotificationConfig(createConfig); - await deleteNotificationConfig(getConfig); - await deleteNotificationConfig(listConfig); - await deleteNotificationConfig(updateConfig); + await deleteNotificationConfigIfExists(createConfig); + await deleteNotificationConfigIfExists(getConfig); + await deleteNotificationConfigIfExists(listConfig); + await deleteNotificationConfigIfExists(updateConfig); }); it('client can create config', () => { diff --git a/security-center/snippets/system-test/v2/assetSecurityMarks.test.js b/security-center/snippets/system-test/v2/assetSecurityMarks.test.js new file mode 100644 index 0000000000..968f724458 --- /dev/null +++ b/security-center/snippets/system-test/v2/assetSecurityMarks.test.js @@ -0,0 +1,82 @@ +// Copyright 2024 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 +// +// https://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'; + +const {SecurityCenterClient} = require('@google-cloud/security-center'); +const {assert} = require('chai'); +const {describe, it, before} = require('mocha'); +const {execSync} = require('child_process'); + +// TODO(developers): update for your own environment +const organizationId = '1081635000895'; + +describe('client with security marks for assets', async () => { + let data; + before(async () => { + // Creates a new client. + const client = new SecurityCenterClient(); + + const [assetResults] = await client.listAssets({ + parent: client.organizationPath(organizationId), + }); + const randomAsset = assetResults[0].asset; + console.log('random %j', randomAsset); + data = { + orgId: organizationId, + assetName: randomAsset.name, + }; + console.log('data %j', data); + }); + it('client can add security marks to asset.', () => { + const output = execSync( + `node v2/addSecurityMarks.js ${data.assetName}` + ).toString(); + assert.include(output, data.assetName); + assert.match(output, /key_a/); + assert.match(output, /value_a/); + assert.match(output, /key_b/); + assert.match(output, /value_b/); + assert.notMatch(output, /undefined/); + }); + + it('client can add and delete security marks', () => { + // Ensure marks are set. + execSync(`node v2/addSecurityMarks.js ${data.assetName}`).toString(); + + const output = execSync( + `node v2/addDeleteSecurityMarks.js ${data.assetName}` + ).toString(); + assert.match(output, /key_a/); + assert.match(output, /new_value_a/); + assert.notMatch(output, /key_b/); + assert.notMatch(output, /undefined/); + }); + + it('client can delete security marks', () => { + // Ensure marks are set. + execSync(`node v2/addSecurityMarks.js ${data.assetName}`).toString(); + + const output = execSync( + `node v2/deleteAssetsSecurityMarks.js ${data.assetName}` + ).toString(); + assert.notMatch(output, /key_a/); + assert.notMatch(output, /value_a/); + assert.notMatch(output, /key_b/); + assert.notMatch(output, /value_b/); + assert.include(output, data.assetName); + assert.include(output, data.assetName); + assert.notMatch(output, /undefined/); + }); +}); diff --git a/security-center/snippets/v2/addDeleteSecurityMarks.js b/security-center/snippets/v2/addDeleteSecurityMarks.js new file mode 100644 index 0000000000..2e2cd008d4 --- /dev/null +++ b/security-center/snippets/v2/addDeleteSecurityMarks.js @@ -0,0 +1,49 @@ +// Copyright 2024 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'; + +/** + * Demonstrates adding/updating at the same time as deleting security + * marks from an asset. + */ +function main(assetName = 'full asset path to add marks to') { + // [START securitycenter_add_delete_security_marks_v2] + // Imports the Google Cloud client library. + const {SecurityCenterClient} = require('@google-cloud/security-center').v2; + + // Creates a new client. + const client = new SecurityCenterClient(); + + async function addDeleteSecurityMarks() { + // assetName is the full resource path for the asset to update. + // Specify the value of 'assetName' in one of the following formats: + // `organizations/${org-id}/assets/${asset-id}`; + // `projects/${project-id}/assets/${asset-id}`; + // `folders/${folder-id}/assets/${asset-id}`; + const [newMarks] = await client.updateSecurityMarks({ + securityMarks: { + name: `${assetName}/securityMarks`, + marks: {key_a: 'new_value_a'}, + }, + // Only update the enableAssetDiscovery field. + updateMask: {paths: ['marks.key_a', 'marks.key_b']}, + }); + + console.log('New marks: %j', newMarks); + } + addDeleteSecurityMarks(); + // [END securitycenter_add_delete_security_marks_v2] +} + +main(...process.argv.slice(2)); diff --git a/security-center/snippets/v2/addSecurityMarks.js b/security-center/snippets/v2/addSecurityMarks.js new file mode 100644 index 0000000000..cbd69e727d --- /dev/null +++ b/security-center/snippets/v2/addSecurityMarks.js @@ -0,0 +1,50 @@ +// Copyright 2024 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'; + +/** + * Demostrates adding security marks to an asset. + */ +function main(assetName = 'full asset path to add marks to') { + // [START securitycenter_add_security_marks_v2] + // Imports the Google Cloud client library. + const {SecurityCenterClient} = require('@google-cloud/security-center').v2; + + // Creates a new client. + const client = new SecurityCenterClient(); + + async function addSecurityMarks() { + // assetName is the full resource path for the asset to update. + // Specify the value of 'assetName' in one of the following formats: + // `organizations/${org-id}/assets/${asset-id}`; + // `projects/${project-id}/assets/${asset-id}`; + // `folders/${folder-id}/assets/${asset-id}`; + // const assetName = "organizations/123123342/assets/12312321"; + const [newMarks] = await client.updateSecurityMarks({ + securityMarks: { + name: `${assetName}/securityMarks`, + marks: {key_a: 'value_a', key_b: 'value_b'}, + }, + // Only update the marks with these keys. + updateMask: {paths: ['marks.key_a', 'marks.key_b']}, + }); + + console.log('New marks: %j', newMarks); + } + addSecurityMarks(); + // [END securitycenter_add_security_marks_v2] +} + +main(...process.argv.slice(2)); diff --git a/security-center/snippets/v2/deleteAssetsSecurityMarks.js b/security-center/snippets/v2/deleteAssetsSecurityMarks.js new file mode 100644 index 0000000000..f240731424 --- /dev/null +++ b/security-center/snippets/v2/deleteAssetsSecurityMarks.js @@ -0,0 +1,50 @@ +// Copyright 2024 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'; + +/** + * Demostrates deleting security marks on an asset. + */ +function main(assetName = 'full asset path to add marks to') { + // [START securitycenter_delete_security_marks_v2] + // Imports the Google Cloud client library. + const {SecurityCenterClient} = require('@google-cloud/security-center').v2; + + // Creates a new client. + const client = new SecurityCenterClient(); + + async function deleteSecurityMarks() { + // assetName is the full resource path for the asset to update. + // Specify the value of 'assetName' in one of the following formats: + // `organizations/${org-id}/assets/${asset-id}`; + // `projects/${project-id}/assets/${asset-id}`; + // `folders/${folder-id}/assets/${asset-id}`; + // const assetName = "organizations/123123342/assets/12312321"; + const [newMarks] = await client.updateSecurityMarks({ + securityMarks: { + name: `${assetName}/securityMarks`, + // Intentionally, not setting marks to delete them. + }, + // Only delete marks for the following keys. + updateMask: {paths: ['marks.key_a', 'marks.key_b']}, + }); + + console.log('Updated marks: %j', newMarks); + } + deleteSecurityMarks(); + // [END securitycenter_delete_security_marks_v2] +} + +main(...process.argv.slice(2));