-
Notifications
You must be signed in to change notification settings - Fork 2.9k
feat(security-center): Add Resource v2 API Assets Security Marks Samples #9680
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
c64abfb
8c76982
1d4693b
406c411
38f9e26
99eacfc
d06981b
e4b8d95
885be93
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
/* | ||
* Copyright 2025 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. | ||
*/ | ||
|
||
// [START securitycenter_add_delete_security_marks_assets_v2] | ||
|
||
package vtwo.assets; | ||
|
||
import com.google.cloud.securitycenter.v2.SecurityCenterClient; | ||
import com.google.cloud.securitycenter.v2.SecurityMarks; | ||
import com.google.cloud.securitycenter.v2.UpdateSecurityMarksRequest; | ||
import com.google.protobuf.FieldMask; | ||
import java.io.IOException; | ||
|
||
public class AddDeleteSecurityMarks { | ||
public static void main(String[] args) throws IOException { | ||
// organizationId: Google Cloud Organization id. | ||
String organizationId = "ORGANIZATION_ID"; | ||
|
||
// Specify the asset id. | ||
Comment on lines
+29
to
+32
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TODO (actionable comments) are required here to instruct a reader how to create a working example. |
||
String assetId = "ASSET_ID"; | ||
|
||
addAndDeleteSecurityMarks(organizationId, assetId); | ||
} | ||
|
||
public static SecurityMarks addAndDeleteSecurityMarks(String organizationId, String assetId) | ||
throws IOException { | ||
// Initialize client that will be used to send requests. This client only needs to be created | ||
// once, and can be reused for multiple requests. | ||
try (SecurityCenterClient client = SecurityCenterClient.create()) { | ||
|
||
// Specify the value of 'assetName' in one of the following formats: | ||
// String assetName = "organizations/{org-id}/assets/{asset-id}"; | ||
String assetName = String.format("organizations/%s/assets/%s", organizationId, assetId); | ||
|
||
// Start setting up a request to clear and update security marks for an asset. | ||
// Create security mark and field mask for clearing security marks. | ||
SecurityMarks securityMarks = | ||
SecurityMarks.newBuilder() | ||
.setName(assetName + "/securityMarks") | ||
.putMarks("key_a", "new_value_for_a") | ||
.putMarks("key_b", "new_value_for_b") | ||
.build(); | ||
|
||
// Define the paths in the updateMask that correspond to the keys being updated in | ||
// securityMarks. | ||
FieldMask updateMask = | ||
FieldMask.newBuilder().addPaths("marks.key_a").addPaths("marks.key_b").build(); | ||
|
||
// Create the request to update security marks. | ||
UpdateSecurityMarksRequest request = | ||
UpdateSecurityMarksRequest.newBuilder() | ||
.setSecurityMarks(securityMarks) | ||
.setUpdateMask(updateMask) | ||
.build(); | ||
|
||
// Call the API and return the response. | ||
SecurityMarks response = client.updateSecurityMarks(request); | ||
return response; | ||
minherz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} | ||
} | ||
// [END securitycenter_add_delete_security_marks_assets_v2] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
/* | ||
* Copyright 2025 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. | ||
*/ | ||
|
||
// [START securitycenter_add_security_marks_assets_v2] | ||
|
||
package vtwo.assets; | ||
|
||
import autovalue.shaded.com.google.common.collect.ImmutableMap; | ||
import com.google.cloud.securitycenter.v2.SecurityCenterClient; | ||
import com.google.cloud.securitycenter.v2.SecurityMarks; | ||
import com.google.cloud.securitycenter.v2.UpdateSecurityMarksRequest; | ||
import com.google.protobuf.FieldMask; | ||
import java.io.IOException; | ||
|
||
public class AddSecurityMarksToAssets { | ||
|
||
public static void main(String[] args) throws IOException { | ||
// organizationId: Google Cloud Organization id. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TODO (actionable comments) are required here to instruct a reader how to create a working example. |
||
String organizationId = "ORGANIZATION_ID"; | ||
|
||
// Specify the asset id. | ||
String assetId = "ASSET_ID"; | ||
|
||
addToAsset(organizationId, assetId); | ||
} | ||
|
||
public static SecurityMarks addToAsset(String organizationId, String assetId) throws IOException { | ||
// Initialize client that will be used to send requests. This client only needs to be created | ||
// once, and can be reused for multiple requests. | ||
try (SecurityCenterClient client = SecurityCenterClient.create()) { | ||
|
||
// Specify the value of 'assetName' in one of the following formats: | ||
// String assetName = "organizations/{org-id}/assets/{asset-id}"; | ||
String assetName = String.format("organizations/%s/assets/%s", organizationId, assetId); | ||
|
||
// Start setting up a request to add security marks for a finding. | ||
ImmutableMap markMap = ImmutableMap.of("key_a", "value_a", "key_b", "value_b"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: consider passing the collection of key/value strings as an argument in order to make the example more usable. |
||
|
||
// Add security marks and field mask for security marks. | ||
SecurityMarks securityMarks = | ||
SecurityMarks.newBuilder() | ||
.setName(assetName + "/securityMarks") | ||
.putAllMarks(markMap) | ||
.build(); | ||
|
||
// Set the update mask to specify which properties should be updated. | ||
// If empty, all mutable fields will be updated. | ||
// For more info on constructing field mask path, see the proto or: | ||
// https://cloud.google.com/java/docs/reference/protobuf/latest/com.google.protobuf.FieldMask | ||
FieldMask updateMask = | ||
FieldMask.newBuilder().addPaths("marks.key_a").addPaths("marks.key_b").build(); | ||
|
||
UpdateSecurityMarksRequest request = | ||
UpdateSecurityMarksRequest.newBuilder() | ||
.setSecurityMarks(securityMarks) | ||
.setUpdateMask(updateMask) | ||
.build(); | ||
|
||
// Call the API and return the response. | ||
SecurityMarks response = client.updateSecurityMarks(request); | ||
return response; | ||
minherz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} | ||
} | ||
|
||
// [END securitycenter_add_security_marks_assets_v2] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
/* | ||
* Copyright 2025 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. | ||
*/ | ||
|
||
// [START securitycenter_delete_security_marks_assets_v2] | ||
|
||
package vtwo.assets; | ||
|
||
import com.google.cloud.securitycenter.v2.SecurityCenterClient; | ||
import com.google.cloud.securitycenter.v2.SecurityMarks; | ||
import com.google.cloud.securitycenter.v2.UpdateSecurityMarksRequest; | ||
import com.google.protobuf.FieldMask; | ||
import java.io.IOException; | ||
|
||
public class DeleteAssetsSecurityMarks { | ||
public static void main(String[] args) throws IOException { | ||
// organizationId: Google Cloud Organization id. | ||
String organizationId = "ORGANIZATION_ID"; | ||
|
||
// Specify the asset-id. | ||
String assetId = "ASSET_ID"; | ||
|
||
deleteSecurityMarks(organizationId, assetId); | ||
} | ||
|
||
public static SecurityMarks deleteSecurityMarks(String organizationId, String assetId) | ||
throws IOException { | ||
// Initialize client that will be used to send requests. This client only needs to be created | ||
// once, and can be reused for multiple requests. | ||
try (SecurityCenterClient client = SecurityCenterClient.create()) { | ||
|
||
// Specify the value of 'assetName' in one of the following formats: | ||
// String assetName = "organizations/{org-id}/assets/{asset-id}"; | ||
String assetName = String.format("organizations/%s/assets/%s", organizationId, assetId); | ||
|
||
// Start setting up a request to clear and update security marks for an asset. | ||
// Create security mark and field mask for clearing security marks. | ||
SecurityMarks securityMarks = | ||
SecurityMarks.newBuilder().setName(assetName + "/securityMarks").build(); | ||
|
||
FieldMask updateMask = | ||
FieldMask.newBuilder().addPaths("marks.key_a").addPaths("marks.key_b").build(); | ||
|
||
UpdateSecurityMarksRequest request = | ||
UpdateSecurityMarksRequest.newBuilder() | ||
.setSecurityMarks(securityMarks) | ||
.setUpdateMask(updateMask) | ||
.build(); | ||
|
||
// Call the API. | ||
SecurityMarks response = client.updateSecurityMarks(request); | ||
return response; | ||
minherz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} | ||
} | ||
|
||
// [END securitycenter_delete_security_marks_assets_v2] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
/* | ||
* Copyright 2025 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. | ||
*/ | ||
|
||
package vtwo; | ||
|
||
// import static org.junit.Assert.assertThat; | ||
import static com.google.common.truth.Truth.assertThat; | ||
import static junit.framework.TestCase.assertFalse; | ||
import static junit.framework.TestCase.assertTrue; | ||
|
||
import com.google.cloud.testing.junit4.MultipleAttemptsRule; | ||
import com.google.gson.JsonObject; | ||
import com.google.gson.JsonParser; | ||
import java.io.ByteArrayOutputStream; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.nio.charset.StandardCharsets; | ||
import java.util.regex.Matcher; | ||
import java.util.regex.Pattern; | ||
import org.junit.After; | ||
import org.junit.AfterClass; | ||
import org.junit.Before; | ||
import org.junit.BeforeClass; | ||
import org.junit.Rule; | ||
import org.junit.Test; | ||
import org.junit.runner.RunWith; | ||
import org.junit.runners.JUnit4; | ||
import vtwo.assets.AddDeleteSecurityMarks; | ||
import vtwo.assets.AddSecurityMarksToAssets; | ||
import vtwo.assets.DeleteAssetsSecurityMarks; | ||
|
||
@RunWith(JUnit4.class) | ||
public class AssetSecurityMarksIT { | ||
|
||
private static final String ORGANIZATION_ID = System.getenv("SCC_PROJECT_ORG_ID"); | ||
private static String assetId; | ||
private static ByteArrayOutputStream stdOut; | ||
|
||
@Rule | ||
public final MultipleAttemptsRule multipleAttemptsRule = | ||
new MultipleAttemptsRule(3, 120000); // 2 minutes | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 2 minutes per test is too long. please consider to reduce the maximal time of execution. |
||
|
||
// Check if the required environment variables are set. | ||
public static void requireEnvVar(String envVarName) { | ||
assertThat(System.getenv(envVarName)).isNotEmpty(); | ||
} | ||
|
||
// Extracts the asset ID from a full resource name. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it is a good practice to explain regex expressions. consider adding that it looks for a suffix composed of one or more digits after the last forward slash. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Addressed. |
||
// This regex pattern matches the last segment of the resource name, | ||
// which consists of digits after the final forward slash (e.g., "assets/12345"). | ||
private static String extractAssetId(String assetPath) { | ||
// Pattern to match the asset ID at the end of the resource name. | ||
Pattern pattern = Pattern.compile("assets/([^/]+)$"); | ||
Matcher matcher = pattern.matcher(assetPath); | ||
if (matcher.find()) { | ||
return matcher.group(1); | ||
} | ||
return assetPath; | ||
} | ||
|
||
@BeforeClass | ||
public static void setUp() throws IOException, InterruptedException { | ||
|
||
// Validate required environment variables. | ||
requireEnvVar("SCC_PROJECT_ORG_ID"); | ||
|
||
// Load static_asset.json from resources | ||
// Since there are no APIs to create an Asset | ||
InputStream inputStream = | ||
AssetSecurityMarksIT.class.getClassLoader().getResourceAsStream("static_asset.json"); | ||
|
||
if (inputStream == null) { | ||
throw new IOException("static_asset.json file not found in resources."); | ||
} | ||
|
||
// Convert InputStream to String | ||
String jsonContent = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8); | ||
|
||
// Parse JSON (using Gson) | ||
JsonObject jsonObject = JsonParser.parseString(jsonContent).getAsJsonObject(); | ||
|
||
// Extract assetId from mock data | ||
assetId = extractAssetId(jsonObject.get("name").getAsString()); | ||
|
||
if (assetId == null || assetId.isEmpty()) { | ||
throw new IllegalStateException("Asset ID is missing from static_asset.json"); | ||
} | ||
} | ||
|
||
@Before | ||
public void beforeEach() { | ||
stdOut = new ByteArrayOutputStream(); | ||
} | ||
|
||
@After | ||
public void afterEach() { | ||
stdOut = null; | ||
System.setOut(null); | ||
} | ||
|
||
@AfterClass | ||
public static void cleanUp() { | ||
System.setOut(System.out); | ||
} | ||
Comment on lines
+103
to
+117
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove this code since code samples do not print to stdout. |
||
|
||
@Test | ||
public void testAddSecurityMarksToAsset() throws IOException { | ||
com.google.cloud.securitycenter.v2.SecurityMarks response = | ||
minherz marked this conversation as resolved.
Show resolved
Hide resolved
minherz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
AddSecurityMarksToAssets.addToAsset(ORGANIZATION_ID, assetId); | ||
|
||
assertTrue(response.getMarksOrThrow("key_a").contains("value_a")); | ||
assertTrue(response.getMarksOrThrow("key_b").contains("value_b")); | ||
} | ||
|
||
@Test | ||
public void testDeleteSecurityMarksOnAsset() throws IOException { | ||
com.google.cloud.securitycenter.v2.SecurityMarks response = | ||
DeleteAssetsSecurityMarks.deleteSecurityMarks(ORGANIZATION_ID, assetId); | ||
|
||
assertFalse(response.containsMarks("key_a")); | ||
assertFalse(response.containsMarks("key_b")); | ||
} | ||
|
||
@Test | ||
public void testAddAndDeleteSecurityMarks() throws IOException { | ||
com.google.cloud.securitycenter.v2.SecurityMarks response = | ||
AddDeleteSecurityMarks.addAndDeleteSecurityMarks(ORGANIZATION_ID, assetId); | ||
|
||
assertTrue(response.getMarksOrThrow("key_a").contains("new_value_for_a")); | ||
assertTrue(response.getMarksOrThrow("key_b").contains("new_value_for_b")); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The example name is confusing. Adding and deleting marks in the same action is contradicting. Consider changing the name to
UpdateSecurityMarks
. If you want to demonstrate something else, change the name accordingly.