Skip to content

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

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 {
Copy link
Contributor

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.

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
Copy link
Contributor

Choose a reason for hiding this comment

The 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.
See this main() method for an 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;
}
}
}
// [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.
Copy link
Contributor

Choose a reason for hiding this comment

The 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");
Copy link
Contributor

Choose a reason for hiding this comment

The 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;
}
}
}

// [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;
}
}
}

// [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
Copy link
Contributor

Choose a reason for hiding this comment

The 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.
Copy link
Contributor

Choose a reason for hiding this comment

The 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.

Copy link
Author

Choose a reason for hiding this comment

The 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
Copy link
Contributor

Choose a reason for hiding this comment

The 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 =
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"));
}
}
Loading