Tanzu Spring Commercial

Custom Standards Support and Validation

Last Updated February 28, 2025

The Enterprise Spring Boot Governance Starter governance-starter library supports adding and validating custom specifications. This feature allows you to incorporate organization-specific regulations, industry guidelines, or proprietary standards into your validation processes.

To run validation against custom specifications, follow these steps:

  1. Add custom governance specs by implementing the GovernanceSpecProvider bean.
  2. Create a class in which to store your collected information.
  3. Implement a GovernanceDetailsScanner bean to gather details and populate the class created in the previous step.
  4. Implement a GovernanceValidator bean to validate against the collected data.

A spec id can only be validated by a single validator. A validator can only validate a single spec id.
That is, a spec id has a 1:1 mapping to a GovernanceValidator bean.

Define a GovernanceSpecProvider bean to add custom specs

To add custom governance specs, see the following example:

package com.example.compliance;

import com.vmware.tanzu.spring.governance.spec.GovernanceSpec;
import com.vmware.tanzu.spring.governance.spec.GovernanceSpecProvider;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class ExampleOrgGovernanceSpecProvider implements GovernanceSpecProvider {

	@Override
	public List<GovernanceSpec> getSpecs() {
		return List.of(getSpec());
	}

	private static GovernanceSpec getSpec() {
		var spec = new GovernanceSpec();
		spec.setId("MY-ORG-0001");
		spec.setTitle("TLS must be enabled");
		spec.setDescription("As per org rules, all apps must have TLS enabled");
		spec.setOrg("com.example");
		spec.setTags(List.of("MY-ORG"));
		return spec;
	}
}

​Create a custom class to store application details

To create a class in which to store your collected information, see the following example of a custom class:

public record ExampleOrgComplianceDetails(
	boolean serverTlsEnabled,
	boolean managementTlsEnabled) { }

Define a GovernanceDetailsScanner bean

Gather application details and populate the class created earlier. Implement the interface methods, where:

  • getKey() is the key for the details object. In the validator bean, a map will be provided. Use this key to fetch the details object from the map.
  • scan() returns an instance of the collected details object.
package com.example.compliance;

import com.vmware.tanzu.spring.governance.GovernanceDetailsScanner;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementServerProperties;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.stereotype.Component;

@Component
public class ExampleOrgDetailsScanner implements GovernanceDetailsScanner {

	static final String KEY = "exampleDetails";
	private final ServerProperties serverProperties;
	private final ManagementServerProperties managementServerProperties;

	ExampleOrgDetailsScanner(ServerProperties serverProperties,
		ManagementServerProperties managementServerProperties) {
		this.serverProperties = serverProperties;
		this.managementServerProperties = managementServerProperties;
	}

	@Override
	public String getKey() {
		return KEY;
	}

	@Override
	public Object scan() {
		var serverTlsEnabled = serverProperties.getSsl() != null
			&& serverProperties.getSsl().isEnabled();
		var actuatorIsUsingSameTlsConfig = serverTlsEnabled
			&& managementServerProperties.getSsl() == null;
		var actuatorHasSeparateTlsConfig = managementServerProperties.getSsl() != null
			&& managementServerProperties.getSsl().isEnabled();
		var managementTlsEnabled = actuatorIsUsingSameTlsConfig || actuatorHasSeparateTlsConfig;
		return new ExampleOrgComplianceDetails(serverTlsEnabled, managementTlsEnabled);
	}
}

Create a GovernanceValidator bean to run your validation rules

Implement the interface methods, where:

  • requiresKey() is the key defined in the scanner where this validator can find the details.
  • appliesToSpec() where the validator returns the GovernanceSpec it validates.
  • validate() where the validator returns a List<ValidationTestRun> after validating the details.
package com.example.compliance;

import com.vmware.tanzu.spring.governance.GovernanceValidator;
import com.vmware.tanzu.governance.ValidationState;
import com.vmware.tanzu.spring.governance.ValidationTestRun;
import com.vmware.tanzu.spring.governance.spec.GovernanceSpec;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;

@Component
public class ExampleOrgTlsEnabledValidator implements GovernanceValidator {

	private static final String ID = "MY-ORG-0001";

	@Override
	public String requiresKey() {
		return ExampleOrgDetailsScanner.KEY;
	}

	@Override
	public GovernanceSpec appliesToSpec(List<GovernanceSpec> list) {
		return list.stream()
			.filter(spec -> ID.equals(spec.getId()))
			.findFirst()
			.orElse(null);
	}

	@Override
	public List<ValidationTestRun> validate(Map<String, Object> appDetails) {
		ExampleOrgComplianceDetails exampleDetails = (ExampleOrgComplianceDetails) getDetails(appDetails);

		var serverTlsEnabledTest = new ValidationTestRun();
		var passedTest1 = exampleDetails.serverTlsEnabled() ? ValidationState.PASS : ValidationState.FAIL;
		serverTlsEnabledTest.setState(passedTest1);
		serverTlsEnabledTest.setDescriptionFormat("Observed server tls enabled: %tlsEnabled");
		serverTlsEnabledTest.setParameters(Map.of("tlsEnabled", passedTest1));

		var managementTlsEnabledTest = new ValidationTestRun();
		var passedTest2 = exampleDetails.managementTlsEnabled() ? ValidationState.PASS : ValidationState.FAIL;
		managementTlsEnabledTest.setState(passedTest2);
		managementTlsEnabledTest.setDescriptionFormat("Observed management tls enabled: %tlsEnabled");
		managementTlsEnabledTest.setParameters(Map.of("tlsEnabled", passedTest2));

		return List.of(serverTlsEnabledTest, managementTlsEnabledTest);
	}
}

Also note:

  • The interface method getDetails() returns the details from the appDetails Map using the key.

  • The default interface method appliesToDetails(Map<String, Object> appDetails) (not shown) can be overridden to configure whether the validator should be run against the details. When it returns false, validate() is not executed. The total test cases do not include this test.

  • The string in ValidationTestRun.setDescriptionFormat() can include parameters; for example, "Observed management tls enabled: %tlsEnabled". These parameters must be present as keys in the Map for ValidationTestRun.setParameters(). In the output JSON, the value will be used; for example, “Description”: “Observed server tls enabled: true”

Validation State

The test result is represented by the ValidationState:

  • PASS - the test succeeded
  • FAIL - the test failed
  • UNKNOWN - an issue occurred while collecting data or running the test.
    For example, the library uses reflection while collecting the configuration of the application. In the case where reflection fails, the result is treated as UNKNOWN. If you encounter this result when running the pre-defined tests, contact Broadcom Support with your use case.

If there are failing or unknown tests, the library forces the application to shut down. However, you can bypass the shutdown by deactivating the specific test, or by deactivating the exit-on-failure flag.

See Library Configuration Options for further instructions.

Run the application

Run the app and access the Governance Endpoint.
Filter by the tag for your spec: https://localhost:8443/actuator/governance?tag=MY-ORG.

Observe the details field in the JSON that includes a field, exampleDetails, from the ExampleOrgDetailsScanner. You will see the test run result shows failure.

Set the management port on a separate port,; then the test will pass.

management:
  server:
    port: 9443