accounts = response.accounts();
+ if (accounts == null || accounts.isEmpty()) {
+ logger.info(" No account information returned.");
+ return;
+ }
+
+ for (AccountState account : accounts) {
+ logger.info(" Account: " + account.accountId());
+ ResourceState resources = account.resourceState();
+ if (resources == null) {
+ System.out.println(" No resource state data available.");
+ continue;
+ }
+
+ logger.info(" Resource States:");
+ printState("EC2", resources.ec2());
+ printState("ECR", resources.ecr());
+ printState("Lambda", resources.lambda());
+ printState("Lambda Code", resources.lambdaCode());
+ System.out.println();
+ }
+
+ } catch (Inspector2Exception e) {
+ System.err.println(" Failed to retrieve account status: " + e.awsErrorDetails().errorMessage());
+ }
+ }
+
+ public static void printState(String name, State state) {
+ if (state == null) {
+ logger.info(" - {} : (no data)", name);
+ return;
+ }
+ String err = state.errorMessage() != null ? " (Error: " + state.errorMessage() + ")" : "";
+ logger.info(" - {}: {}{}", name, state.status(), err);
+ }
+
+ /**
+ * Lists recent findings from AWS Inspector2 using the synchronous client with a paginator.
+ *
+ * @param inspectorClient an instance of {@link Inspector2Client} used to call AWS Inspector2
+ * @throws Inspector2Exception if there is an error communicating with the Inspector2 service
+ */
+ /**
+ * Lists up to 10 recent findings from AWS Inspector2 using the synchronous client.
+ *
+ * This method retrieves findings in pages and logs details for each finding,
+ * including title, severity, status, and last observed time. Only the first
+ * 10 findings are logged, even if more exist.
+ *
+ * @param inspectorClient an instance of {@link Inspector2Client} used to call AWS Inspector2
+ * @throws Inspector2Exception if there is an error communicating with the Inspector2 service
+ */
+ public static void listRecentFindings(Inspector2Client inspectorClient) {
+ final int MAX_FINDINGS = 10;
+ int totalLogged = 0;
+
+ try {
+ // Build initial request with page size
+ ListFindingsRequest request = ListFindingsRequest.builder()
+ .maxResults(MAX_FINDINGS)
+ .build();
+
+ // Paginator returns an iterable over responses
+ ListFindingsIterable responses = inspectorClient.listFindingsPaginator(request);
+
+ for (ListFindingsResponse response : responses) {
+ List findings = response.findings();
+ if (findings == null || findings.isEmpty()) {
+ continue;
+ }
+
+ for (Finding finding : findings) {
+ if (totalLogged >= MAX_FINDINGS) {
+ break;
+ }
+
+ logger.info(" Title: {}", finding.title());
+ logger.info(" Severity: {}", finding.severity());
+ logger.info(" Status: {}", finding.status());
+ logger.info(" Last Observed: {}", finding.lastObservedAt());
+ logger.info("");
+
+ totalLogged++;
+ }
+
+ if (totalLogged >= MAX_FINDINGS) {
+ break;
+ }
+ }
+
+ if (totalLogged == 0) {
+ logger.info(" No findings found.");
+ } else {
+ logger.info(" Displayed {} recent finding(s).", totalLogged);
+ }
+
+ } catch (Inspector2Exception e) {
+ logger.info(" Error listing findings: {}", e.awsErrorDetails().errorMessage());
+ }
+ }
+
+
+ /**
+ * Displays the usage totals for the Inspector2 service.
+ *
+ * @param inspectorClient the {@code Inspector2Client} used to make the API call to
+ * retrieve the usage totals.
+ *
+ * @throws Inspector2Exception if there is an error while retrieving the usage totals.
+ * The error message is printed to the standard error output.
+ */
+ public static void showUsageTotals(Inspector2Client inspectorClient) {
+ try {
+ logger.info("Listing usage totals using paginator...");
+ ListUsageTotalsRequest request = ListUsageTotalsRequest.builder()
+ .maxResults(10)
+ .build();
+
+ // Create paginator.
+ ListUsageTotalsIterable paginator = inspectorClient.listUsageTotalsPaginator(request);
+ List allTotals = new ArrayList<>();
+
+ // Iterate through all pages.
+ for (ListUsageTotalsResponse response : paginator) {
+ List totals = response.totals();
+ if (totals != null && !totals.isEmpty()) {
+ allTotals.addAll(totals);
+ }
+ }
+
+ // Display results.
+ if (allTotals.isEmpty()) {
+ logger.info(" No usage data available yet.");
+ logger.info(" Usage data appears after Inspector has been active for some time.");
+ } else {
+ logger.info(" Usage Totals (Last 30 days):");
+ for (UsageTotal total : allTotals) {
+ logger.info(" Account: {}" , total.accountId());
+ if (total.usage() != null && !total.usage().isEmpty()) {
+ total.usage().forEach(u -> {
+ logger.info(" - {}: {}", u.type(), u.total());
+
+ if (u.estimatedMonthlyCost() != null) {
+ logger.info(" Estimated Monthly Cost: {} {}", u.estimatedMonthlyCost(), u.currency());
+ }
+ });
+ }
+ logger.info("");
+ }
+ }
+
+ } catch (Inspector2Exception e) {
+ logger.info(" Error getting usage totals: {}" , e.awsErrorDetails().errorMessage());
+ throw e;
+ } catch (Exception e) {
+ throw new RuntimeException("Unexpected error while listing usage totals: " + e.getMessage(), e);
+ }
+ }
+}
+// snippet-end:[inspector.java2.hello.main]
\ No newline at end of file
diff --git a/javav2/example_code/inspector/src/main/java/com/java/inspector/InspectorActions.java b/javav2/example_code/inspector/src/main/java/com/java/inspector/InspectorActions.java
new file mode 100644
index 00000000000..c51a7788cc0
--- /dev/null
+++ b/javav2/example_code/inspector/src/main/java/com/java/inspector/InspectorActions.java
@@ -0,0 +1,710 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package com.java.inspector;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
+import software.amazon.awssdk.core.retry.RetryMode;
+import software.amazon.awssdk.http.async.SdkAsyncHttpClient;
+import software.amazon.awssdk.http.nio.netty.NettyNioAsyncHttpClient;
+import software.amazon.awssdk.services.inspector2.Inspector2AsyncClient;
+import software.amazon.awssdk.services.inspector2.model.*;
+import software.amazon.awssdk.services.inspector2.paginators.ListFiltersPublisher;
+import software.amazon.awssdk.services.inspector2.paginators.ListFindingsPublisher;
+import software.amazon.awssdk.services.inspector2.paginators.ListUsageTotalsPublisher;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+import java.util.stream.Collectors;
+
+// snippet-start:[inspector.java2_actions.main]
+public class InspectorActions {
+ private static Inspector2AsyncClient inspectorAsyncClient;
+ private static final Logger logger = LoggerFactory.getLogger(InspectorActions.class);
+
+ private static Inspector2AsyncClient getAsyncClient() {
+ if (inspectorAsyncClient == null) {
+ SdkAsyncHttpClient httpClient = NettyNioAsyncHttpClient.builder()
+ .maxConcurrency(100)
+ .connectionTimeout(Duration.ofSeconds(60))
+ .readTimeout(Duration.ofSeconds(60))
+ .writeTimeout(Duration.ofSeconds(60))
+ .build();
+
+ ClientOverrideConfiguration overrideConfig = ClientOverrideConfiguration.builder()
+ .apiCallTimeout(Duration.ofMinutes(2))
+ .apiCallAttemptTimeout(Duration.ofSeconds(90))
+ .retryStrategy(RetryMode.STANDARD)
+ .build();
+
+ inspectorAsyncClient = Inspector2AsyncClient.builder()
+ .httpClient(httpClient)
+ .overrideConfiguration(overrideConfig)
+ .build();
+ }
+ return inspectorAsyncClient;
+ }
+
+ // snippet-start:[inspector.java2.enable.main]
+
+ /**
+ * Enables AWS Inspector for the provided account(s) and default resource types.
+ *
+ * @param accountIds Optional list of AWS account IDs.
+ */
+ public CompletableFuture enableInspectorAsync(List accountIds) {
+
+ // The resource types to enable.
+ List resourceTypes = List.of(
+ ResourceScanType.EC2,
+ ResourceScanType.ECR,
+ ResourceScanType.LAMBDA,
+ ResourceScanType.LAMBDA_CODE
+ );
+
+ // Build the request.
+ EnableRequest.Builder requestBuilder = EnableRequest.builder()
+ .resourceTypes(resourceTypes);
+
+ if (accountIds != null && !accountIds.isEmpty()) {
+ requestBuilder.accountIds(accountIds);
+ }
+
+ EnableRequest request = requestBuilder.build();
+ return getAsyncClient().enable(request)
+ .whenComplete((response, exception) -> {
+ if (exception != null) {
+ Throwable cause = exception.getCause();
+ if (cause instanceof ValidationException) {
+ throw new CompletionException(
+ "Inspector may already be enabled for this account: %s".formatted(cause.getMessage()),
+ cause
+ );
+
+ }
+
+ if (cause instanceof Inspector2Exception) {
+ Inspector2Exception e = (Inspector2Exception) cause;
+ throw new CompletionException(
+ "AWS Inspector2 service error: %s".formatted(e.awsErrorDetails().errorMessage()),
+ cause
+ );
+ }
+
+ throw new CompletionException(
+ "Failed to enable Inspector: %s".formatted(exception.getMessage()),
+ exception
+ );
+ }
+ })
+ .thenApply(response -> {
+ StringBuilder summary = new StringBuilder("Enable results:\n");
+
+ if (response.accounts() == null || response.accounts().isEmpty()) {
+ summary.append("Inspector may already be enabled for all target accounts.");
+ return summary.toString();
+ }
+
+ for (Account account : response.accounts()) {
+ String accountId = account.accountId() != null ? account.accountId() : "Unknown";
+ String status = account.status() != null ? account.statusAsString() : "Unknown";
+ summary.append(" • Account: ").append(accountId)
+ .append(" → Status: ").append(status).append("\n");
+ }
+
+ return summary.toString();
+ });
+ }
+ // snippet-end:[inspector.java2.enable.main]
+
+ // snippet-start:[inspector.java2.list_coverage.stats.main]
+
+ /**
+ * Retrieves and prints the coverage statistics using a paginator.
+ */
+ public CompletableFuture listCoverageStatisticsAsync() {
+ ListCoverageStatisticsRequest request = ListCoverageStatisticsRequest.builder()
+ .build();
+
+ return getAsyncClient().listCoverageStatistics(request)
+ .whenComplete((response, exception) -> {
+ if (exception != null) {
+ Throwable cause = exception.getCause();
+
+ if (cause instanceof ValidationException) {
+ throw new CompletionException(
+ "Validation error listing coverage statistics: %s".formatted(cause.getMessage()),
+ cause
+ );
+ }
+
+ if (cause instanceof Inspector2Exception) {
+ Inspector2Exception e = (Inspector2Exception) cause;
+
+ throw new CompletionException(
+ "Inspector2 service error: %s".formatted(e.awsErrorDetails().errorMessage()),
+ e
+ );
+ }
+
+ throw new CompletionException(
+ "Unexpected error listing coverage statistics: %s".formatted(exception.getMessage()),
+ exception
+ );
+ }
+ })
+ .thenApply(response -> {
+ List countsList = response.countsByGroup();
+ StringBuilder sb = new StringBuilder();
+
+ if (countsList == null || countsList.isEmpty()) {
+ sb.append("No coverage statistics available.\n");
+ return sb.toString();
+ }
+
+ sb.append("Coverage Statistics:\n");
+
+ for (Counts c : countsList) {
+ sb.append(" Group: ").append(c.groupKey()).append("\n")
+ .append(" Total Count: ").append(c.count()).append("\n\n");
+ }
+
+ return sb.toString();
+ });
+ }
+ // snippet-end:[inspector.java2.list_coverage.stats.main]
+
+ // snippet-start:[inspector.java2.list_usage_totals.main]
+
+ /**
+ * Asynchronously lists Inspector2 usage totals using a paginator.
+ *
+ * @param accountIds optional list of account IDs
+ * @param maxResults maximum results per page
+ * @return CompletableFuture completed with formatted summary text
+ */
+ public CompletableFuture listUsageTotalsAsync(
+ List accountIds,
+ int maxResults) {
+
+ logger.info("Starting usage totals paginator…");
+
+ ListUsageTotalsRequest.Builder builder = ListUsageTotalsRequest.builder()
+ .maxResults(maxResults);
+
+ if (accountIds != null && !accountIds.isEmpty()) {
+ builder.accountIds(accountIds);
+ }
+
+ ListUsageTotalsRequest request = builder.build();
+ ListUsageTotalsPublisher paginator = getAsyncClient().listUsageTotalsPaginator(request);
+ StringBuilder summaryBuilder = new StringBuilder();
+
+ return paginator.subscribe(response -> {
+ if (response.totals() != null && !response.totals().isEmpty()) {
+ response.totals().forEach(total -> {
+ if (total.usage() != null) {
+ total.usage().forEach(usage -> {
+ logger.info("Usage: {} = {}", usage.typeAsString(), usage.total());
+ summaryBuilder.append(usage.typeAsString())
+ .append(": ")
+ .append(usage.total())
+ .append("\n");
+ });
+ }
+ });
+ } else {
+ logger.info("Page contained no usage totals.");
+ }
+ }).thenRun(() -> logger.info("Successfully listed usage totals."))
+ .thenApply(v -> {
+ String summary = summaryBuilder.toString();
+ return summary.isEmpty() ? "No usage totals found." : summary;
+ }).exceptionally(ex -> {
+ Throwable cause = ex.getCause() != null ? ex.getCause() : ex;
+
+ if (cause instanceof ValidationException ve) {
+ throw new CompletionException(
+ "Validation error listing usage totals: %s".formatted(ve.getMessage()),
+ ve
+ );
+ }
+
+ throw new CompletionException("Failed to list usage totals", cause);
+ });
+ }
+
+ // snippet-end:[inspector.java2.list_usage_totals.main]
+
+ // snippet-start:[inspector.java2.get_account_status.main]
+
+ /**
+ * Retrieves the account status using the Inspector2Client.
+ */
+ public CompletableFuture getAccountStatusAsync() {
+ BatchGetAccountStatusRequest request = BatchGetAccountStatusRequest.builder()
+ .accountIds(Collections.emptyList())
+ .build();
+
+ return getAsyncClient().batchGetAccountStatus(request)
+ .whenComplete((response, exception) -> {
+ if (exception != null) {
+ Throwable cause = exception.getCause();
+ if (cause instanceof AccessDeniedException) {
+ throw new CompletionException(
+ "You do not have sufficient access: %s".formatted(cause.getMessage()),
+ cause
+ );
+
+ }
+
+ if (cause instanceof Inspector2Exception) {
+ Inspector2Exception e = (Inspector2Exception) cause;
+
+ throw new CompletionException(
+ "Inspector2 service error: %s".formatted(e.awsErrorDetails().errorMessage()),
+ e
+ );
+ }
+
+ throw new CompletionException(
+ "Unexpected error getting account status: %s".formatted(exception.getMessage()),
+ exception
+ );
+ }
+ })
+ .thenApply(response -> {
+
+ StringBuilder sb = new StringBuilder();
+ List accounts = response.accounts();
+
+ if (accounts == null || accounts.isEmpty()) {
+ sb.append("No account status returned.\n");
+ return sb.toString();
+ }
+
+ sb.append("Inspector Account Status:\n");
+ for (AccountState account : accounts) {
+
+ String accountId = account.accountId() != null
+ ? account.accountId()
+ : "Unknown";
+
+ sb.append(" Account ID: ").append(accountId).append("\n");
+
+ // Overall account state
+ if (account.state() != null && account.state().status() != null) {
+ sb.append(" Overall State: ")
+ .append(account.state().status())
+ .append("\n");
+ } else {
+ sb.append(" Overall State: Unknown\n");
+ }
+
+ // Resource state (only status available)
+ ResourceState resources = account.resourceState();
+ if (resources != null) {
+ sb.append(" Resource Status: available\n");
+ }
+
+ sb.append("\n");
+ }
+
+ return sb.toString();
+ });
+ }
+ // snippet-end:[inspector.java2.get_account_status.main]
+
+ // snippet-start:[inspector.java2.list_filters.main]
+
+ /**
+ * Asynchronously lists Inspector2 filters using a paginator.
+ *
+ * @param maxResults maximum filters per page (nullable)
+ * @return CompletableFuture completed with summary text
+ */
+ public CompletableFuture listFiltersAsync(Integer maxResults) {
+ logger.info("Starting async filters paginator…");
+
+ ListFiltersRequest.Builder builder = ListFiltersRequest.builder();
+ if (maxResults != null) {
+ builder.maxResults(maxResults);
+ }
+
+ ListFiltersRequest request = builder.build();
+
+ // Paginator from SDK
+ ListFiltersPublisher paginator = getAsyncClient().listFiltersPaginator(request);
+ StringBuilder collectedFilterIds = new StringBuilder();
+
+ return paginator.subscribe(response -> {
+ response.filters().forEach(filter -> {
+ logger.info("Filter: " + filter.arn());
+ collectedFilterIds.append(filter.arn()).append("\n");
+ });
+ }).thenApply(v -> {
+ String result = collectedFilterIds.toString();
+ logger.info("Successfully listed all filters.");
+ return result.isEmpty() ? "No filters found." : result;
+ }).exceptionally(ex -> {
+ Throwable cause = ex.getCause() != null ? ex.getCause() : ex;
+
+ if (cause instanceof ValidationException ve) {
+ throw new CompletionException(
+ "Validation error listing filters: %s".formatted(ve.getMessage()),
+ ve
+ );
+ }
+
+ throw new RuntimeException("Failed to list filters", ex);
+ });
+ }
+ // snippet-end:[inspector.java2.list_filters.main]
+
+ // snippet-start:[inspector.java2.create.filter.main]
+
+ /**
+ * Creates a new LOW severity filter in AWS Inspector2 to suppress findings.
+ *
+ * @param filterName the name of the filter to create
+ * @param description a descriptive string explaining the purpose of the filter
+ * @return a CompletableFuture that completes with the ARN of the created filter
+ * @throws CompletionException wraps any validation, Inspector2 service, or unexpected errors
+ */
+ public CompletableFuture createLowSeverityFilterAsync(
+ String filterName,
+ String description) {
+
+ // Define a filter to match LOW severity findings.
+ StringFilter severityFilter = StringFilter.builder()
+ .value(Severity.LOW.toString())
+ .comparison(StringComparison.EQUALS)
+ .build();
+
+ // Create filter criteria.
+ FilterCriteria filterCriteria = FilterCriteria.builder()
+ .severity(Collections.singletonList(severityFilter))
+ .build();
+
+ // Build the filter creation request.
+ CreateFilterRequest request = CreateFilterRequest.builder()
+ .name(filterName)
+ .filterCriteria(filterCriteria)
+ .action(FilterAction.SUPPRESS)
+ .description(description)
+ .build();
+
+ return getAsyncClient().createFilter(request)
+ .whenComplete((response, exception) -> {
+ if (exception != null) {
+ Throwable cause = exception.getCause() != null ? exception.getCause() : exception;
+
+ if (cause instanceof ValidationException ve) {
+ throw new CompletionException(
+ "Validation error creating filter: %s".formatted(ve.getMessage()),
+ ve
+ );
+ }
+
+ if (cause instanceof Inspector2Exception e) {
+ throw new CompletionException(
+ "Inspector2 service error: %s".formatted(e.awsErrorDetails().errorMessage()),
+ e
+ );
+ }
+
+ // Unexpected async error
+ throw new CompletionException(
+ "Unexpected error creating filter: %s".formatted(exception.getMessage()),
+ exception
+ );
+ }
+ })
+ // Extract and return the ARN of the created filter.
+ .thenApply(CreateFilterResponse::arn);
+ }
+ // snippet-end:[inspector.java2.create.filter.main]
+
+ // snippet-start:[inspector.java2.list_findings.main]
+
+ /**
+ * Lists all AWS Inspector findings of LOW severity asynchronously.
+ *
+ * @return CompletableFuture containing either "No findings found." or the ARNs of all LOW findings.
+ */
+ public CompletableFuture listLowSeverityFindingsAsync() {
+ logger.info("Starting async LOW severity findings paginator…");
+
+ // Build a filter criteria for LOW severity.
+ StringFilter severityFilter = StringFilter.builder()
+ .value(Severity.LOW.toString())
+ .comparison(StringComparison.EQUALS)
+ .build();
+
+ FilterCriteria filterCriteria = FilterCriteria.builder()
+ .severity(Collections.singletonList(severityFilter))
+ .build();
+
+ // Build the request.
+ ListFindingsRequest request = ListFindingsRequest.builder()
+ .filterCriteria(filterCriteria)
+ .build();
+
+ ListFindingsPublisher paginator = getAsyncClient().listFindingsPaginator(request);
+ List allArns = Collections.synchronizedList(new ArrayList<>());
+
+ return paginator.subscribe(response -> {
+ if (response.findings() != null && !response.findings().isEmpty()) {
+ response.findings().forEach(finding -> {
+ logger.info("Finding ARN: {}", finding.findingArn());
+ allArns.add(finding.findingArn());
+ });
+ } else {
+ logger.info("Page contained no findings.");
+ }
+ })
+ .thenRun(() -> logger.info("Successfully listed all LOW severity findings."))
+ .thenApply(v -> {
+ if (allArns.isEmpty()) {
+ return "No LOW severity findings found.";
+ } else {
+ return String.join("\n", allArns);
+ }
+ })
+ .exceptionally(ex -> {
+ Throwable cause = ex.getCause() != null ? ex.getCause() : ex;
+ if (cause instanceof ValidationException ve) {
+ throw new CompletionException(
+ "Validation error listing LOW severity findings: %s".formatted(ve.getMessage()),
+ ve
+ );
+ }
+ throw new RuntimeException("Failed to list LOW severity findings", ex);
+ });
+ }
+ // snippet-end:[inspector.java2.list_findings.main]
+
+ // snippet-start:[inspector.java2.list_coverage.main]
+
+ /**
+ * Lists AWS Inspector2 coverage details for scanned resources using a paginator.
+ *
+ * @param maxResults Maximum number of resources to return.
+ */
+ public CompletableFuture listCoverageAsync(
+ int maxResults) {
+
+ ListCoverageRequest request = ListCoverageRequest.builder()
+ .maxResults(maxResults)
+ .build();
+
+ return getAsyncClient().listCoverage(request)
+ .whenComplete((response, exception) -> {
+ if (exception != null) {
+ Throwable cause = exception.getCause();
+
+ if (cause instanceof ValidationException) {
+ throw new CompletionException(
+ "Validation error listing coverage: " + cause.getMessage(),
+ cause
+ );
+ }
+
+ if (cause instanceof Inspector2Exception) {
+ Inspector2Exception e = (Inspector2Exception) cause;
+ throw new CompletionException(
+ "Inspector2 service error: " + e.awsErrorDetails().errorMessage(),
+ e
+ );
+ }
+
+ throw new CompletionException(
+ "Unexpected error listing coverage: " + exception.getMessage(),
+ exception
+ );
+ }
+ })
+ .thenApply(response -> {
+
+ List coveredResources = response.coveredResources();
+
+ // Build output summary
+ StringBuilder sb = new StringBuilder();
+
+ if (coveredResources == null || coveredResources.isEmpty()) {
+ sb.append("No coverage information available.\n")
+ .append("This likely means Inspector hasn't scanned your resources yet ")
+ .append("or no supported resource types are present.\n");
+
+ return sb.toString();
+ }
+
+ // Summary counts
+ sb.append("Coverage Information:\n")
+ .append(" Total resources covered: ")
+ .append(coveredResources.size())
+ .append("\n");
+
+ // Group by resource type
+ Map> byType =
+ coveredResources.stream()
+ .collect(Collectors.groupingBy(CoveredResource::resourceTypeAsString));
+
+ byType.forEach((type, list) ->
+ sb.append(" ").append(type)
+ .append(": ").append(list.size())
+ .append(" resource(s)\n")
+ );
+
+ sb.append("\nSample covered resources:\n");
+ for (int i = 0; i < Math.min(coveredResources.size(), 3); i++) {
+ CoveredResource r = coveredResources.get(i);
+
+ sb.append(" - ")
+ .append(r.resourceTypeAsString())
+ .append(": ")
+ .append(r.resourceId())
+ .append("\n");
+
+ sb.append(" Scan Type: ")
+ .append(r.scanTypeAsString())
+ .append("\n");
+
+ if (r.scanStatus() != null) {
+ sb.append(" Status: ")
+ .append(r.scanStatus().statusCodeAsString())
+ .append("\n");
+ }
+
+ if (r.accountId() != null) {
+ sb.append(" Account ID: ")
+ .append(r.accountId())
+ .append("\n");
+ }
+
+ sb.append("\n");
+ }
+ return sb.toString();
+ });
+ }
+ // snippet-end:[inspector.java2.list_coverage.main]
+
+ // snippet-start:[inspector.java2.delete.filter.main]
+
+ /**
+ * Deletes an AWS Inspector2 filter.
+ *
+ * @param filterARN The ARN of the filter to delete.
+ */
+ public CompletableFuture deleteFilterAsync(String filterARN) {
+ return getAsyncClient().deleteFilter(
+ DeleteFilterRequest.builder()
+ .arn(filterARN)
+ .build()
+ )
+ .handle((response, exception) -> {
+ if (exception != null) {
+ Throwable cause = exception.getCause() != null ? exception.getCause() : exception;
+
+ if (cause instanceof ResourceNotFoundException rnfe) {
+ String msg = "Filter not found for ARN: %s".formatted(filterARN);
+ logger.warn(msg, rnfe);
+ throw new CompletionException(msg, rnfe);
+ }
+
+ throw new RuntimeException("Failed to delete the filter: " + cause, cause);
+ }
+ return null;
+ });
+ }
+ // snippet-end:[inspector.java2.delete.filter.main]
+
+ // snippet-start:[inspector.java2.finding.details.main]
+ /**
+ * Retrieves detailed information about a specific AWS Inspector2 finding asynchronously.
+ *
+ * @param findingArn The ARN of the finding to look up.
+ * @return A {@link CompletableFuture} that, when completed, provides a formatted string
+ * containing all available details for the finding.
+ * @throws RuntimeException if the async call to Inspector2 fails.
+ */
+ public CompletableFuture getFindingDetailsAsync(String findingArn) {
+ BatchGetFindingDetailsRequest request = BatchGetFindingDetailsRequest.builder()
+ .findingArns(findingArn)
+ .build();
+
+ return getAsyncClient().batchGetFindingDetails(request)
+ .thenApply(response -> {
+ if (response.findingDetails() == null || response.findingDetails().isEmpty()) {
+ return String.format("No details found for ARN: ", findingArn);
+ }
+
+ StringBuilder sb = new StringBuilder();
+ response.findingDetails().forEach(detail -> {
+ sb.append("Finding ARN: ").append(detail.findingArn()).append("\n")
+ .append("Risk Score: ").append(detail.riskScore()).append("\n");
+
+ // ExploitObserved timings
+ if (detail.exploitObserved() != null) {
+ sb.append("Exploit First Seen: ").append(detail.exploitObserved().firstSeen()).append("\n")
+ .append("Exploit Last Seen: ").append(detail.exploitObserved().lastSeen()).append("\n");
+ }
+
+ // Reference URLs
+ if (detail.hasReferenceUrls()) {
+ sb.append("Reference URLs:\n");
+ detail.referenceUrls().forEach(url -> sb.append(" • ").append(url).append("\n"));
+ }
+
+ // Tools
+ if (detail.hasTools()) {
+ sb.append("Tools:\n");
+ detail.tools().forEach(tool -> sb.append(" • ").append(tool).append("\n"));
+ }
+
+ // TTPs
+ if (detail.hasTtps()) {
+ sb.append("TTPs:\n");
+ detail.ttps().forEach(ttp -> sb.append(" • ").append(ttp).append("\n"));
+ }
+
+ // CWEs
+ if (detail.hasCwes()) {
+ sb.append("CWEs:\n");
+ detail.cwes().forEach(cwe -> sb.append(" • ").append(cwe).append("\n"));
+ }
+
+ // Evidence
+ if (detail.hasEvidences()) {
+ sb.append("Evidence:\n");
+ detail.evidences().forEach(ev -> {
+ sb.append(" - Severity: ").append(ev.severity()).append("\n");
+
+ });
+ }
+
+ sb.append("\n");
+ });
+
+ return sb.toString();
+ })
+ .exceptionally(ex -> {
+ Throwable cause = ex.getCause() != null ? ex.getCause() : ex;
+
+ if (cause instanceof ResourceNotFoundException rnfe) {
+ return "Finding not found: %s".formatted(findingArn);
+ }
+
+ // Fallback for other exceptions
+ throw new RuntimeException("Failed to get finding details for ARN: " + findingArn, cause);
+ });
+ }
+ // snippet-end:[inspector.java2.finding.details.main]
+}
+// snippet-end:[inspector.java2_actions.main]
\ No newline at end of file
diff --git a/javav2/example_code/inspector/src/main/java/com/java/inspector/InspectorScenario.java b/javav2/example_code/inspector/src/main/java/com/java/inspector/InspectorScenario.java
new file mode 100644
index 00000000000..52e7ae8da1c
--- /dev/null
+++ b/javav2/example_code/inspector/src/main/java/com/java/inspector/InspectorScenario.java
@@ -0,0 +1,185 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+package com.java.inspector;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Scanner;
+
+// snippet-start:[inspector.java2_scenario.main]
+
+/**
+ * Before running this Java V2 code example, set up your development
+ * environment, including your credentials.
+ *
+ * For more information, see the following documentation topic:
+ *
+ * https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html
+ */
+public class InspectorScenario {
+
+ public static final String DASHES = new String(new char[80]).replace("\0", "-");
+ private static final Logger logger = LoggerFactory.getLogger(InspectorScenario.class);
+ private static final Scanner scanner = new Scanner(System.in);
+
+ public static void main(String[] args) {
+ InspectorActions inspectorActions = new InspectorActions();
+ logger.info("Amazon Inspector Basics Scenario");
+
+ logger.info("""
+ Amazon Inspector is a security assessment service provided by Amazon Web Services (AWS) that helps
+ improve the security and compliance of applications deployed on AWS. It automatically assesses
+ applications for vulnerabilities or deviations from best practices. By leveraging Amazon Inspector,
+ users can gain insights into the overall security state of their application and identify potential
+ security risks.
+
+ This service operates by conducting both network and host-based assessments, allowing it to detect a
+ wide range of security issues, including those related to operating systems, network configurations,
+ and application dependencies.
+ """);
+
+ waitForInputToContinue();
+
+ try {
+ runScenario(inspectorActions);
+
+ logger.info("");
+ logger.info("Scenario completed successfully!");
+ logger.info("");
+ logger.info("What you learned:");
+ logger.info(" - How to check Inspector account status");
+ logger.info(" - How to enable Inspector");
+ logger.info(" - How to list and analyze findings");
+ logger.info(" - How to check coverage information");
+ logger.info(" - How to create and manage filters");
+ logger.info(" - How to track usage and costs");
+ logger.info("");
+
+ } catch (Exception ex) {
+ logger.error("Scenario failed due to unexpected error: {}", ex.getMessage(), ex);
+
+ } finally {
+ scanner.close();
+ logger.info("Exiting...");
+ }
+ }
+
+ /**
+ * Runs the Inspector scenario in a step-by-step sequence.
+ *
+ * All InspectorActions methods are asynchronous and return CompletableFutures.
+ * Each step ends with .join().
+ *
+ *
+ * Error handling:
+ * • runScenario() intentionally does not catch any exceptions
+ * • Any async exception thrown during .join() will bubble up
+ * • The main() method contains a single top-level try/catch,
+ * which logs failures and ends the scenario gracefully
+ *
+ * This design keeps the scenario readable while still demonstrating proper
+ * asynchronous Inspector2 usage, pagination, and exception propagation.
+ */
+ public static void runScenario(InspectorActions actions) {
+
+ // Step 1
+ logger.info(DASHES);
+ logger.info("Step 1: Checking Inspector account status...");
+ String status = actions.getAccountStatusAsync().join();
+ logger.info(status);
+ waitForInputToContinue();
+
+ // Step 2
+ logger.info(DASHES);
+ logger.info("Step 2: Enabling Inspector...");
+ String message = actions.enableInspectorAsync(null).join();
+ logger.info(message);
+ waitForInputToContinue();
+
+ // Step 3
+ logger.info(DASHES);
+ logger.info("Step 3: Listing findings...");
+ String allFindings = actions.listLowSeverityFindingsAsync().join();
+
+ if (!allFindings.equals("No findings found.")) {
+ // Split by newline and get the last ARN
+ String[] arns = allFindings.split("\\r?\\n");
+ String lastArn = arns[arns.length - 1];
+
+ // Looks up details
+ logger.info("Look up details on: {}" , lastArn);
+ waitForInputToContinue();
+ String details = actions.getFindingDetailsAsync(lastArn).join() ;
+ logger.info(details);
+ } else {
+ System.out.println("No findings found.");
+ }
+
+ waitForInputToContinue();
+
+ // Step 4
+ logger.info(DASHES);
+ logger.info("Step 4: Listing coverage...");
+ String coverage = actions.listCoverageAsync(5).join();
+ logger.info(coverage);
+ waitForInputToContinue();
+
+ // Step 5
+ logger.info(DASHES);
+ logger.info("Step 5: Creating filter...");
+ String filterName = "suppress-low-" + System.currentTimeMillis();
+ String filterArn = actions
+ .createLowSeverityFilterAsync(filterName, "Suppress low severity findings")
+ .join();
+ logger.info("Created filter: {}", filterArn);
+ waitForInputToContinue();
+
+ // Step 6
+ logger.info(DASHES);
+ logger.info("Step 6: Listing filters...");
+ String filters = actions.listFiltersAsync(10).join();
+ logger.info(filters);
+ waitForInputToContinue();
+
+ // Step 7
+ logger.info(DASHES);
+ logger.info("Step 7: Usage totals...");
+ String usage = actions.listUsageTotalsAsync(null, 10).join();
+ logger.info(usage);
+ waitForInputToContinue();
+
+ // Step 8
+ logger.info(DASHES);
+ logger.info("Step 8: Coverage statistics...");
+ String stats = actions.listCoverageStatisticsAsync().join();
+ logger.info(stats);
+ waitForInputToContinue();
+
+ // Step 9
+ logger.info(DASHES);
+ logger.info("Step 9: Delete filter?");
+ logger.info("Filter ARN: {}", filterArn);
+ logger.info("Delete filter? (y/n)");
+
+ if (scanner.nextLine().trim().equalsIgnoreCase("y")) {
+ actions.deleteFilterAsync(filterArn).join();
+ logger.info("Filter deleted.");
+ }
+
+ waitForInputToContinue();
+ }
+
+ // Utility Method
+ private static void waitForInputToContinue() {
+ while (true) {
+ logger.info("");
+ logger.info("Enter 'c' to continue:");
+ String input = scanner.nextLine().trim();
+ if (input.equalsIgnoreCase("c")) break;
+ logger.info("Invalid input, try again.");
+ }
+ }
+}
+// snippet-end:[inspector.java2_scenario.main]
\ No newline at end of file
diff --git a/javav2/example_code/inspector/src/main/resources/log4j2.xml b/javav2/example_code/inspector/src/main/resources/log4j2.xml
new file mode 100644
index 00000000000..914470047e7
--- /dev/null
+++ b/javav2/example_code/inspector/src/main/resources/log4j2.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/javav2/example_code/inspector/src/test/java/InspectorTests.java b/javav2/example_code/inspector/src/test/java/InspectorTests.java
new file mode 100644
index 00000000000..8ff9b1b2a4b
--- /dev/null
+++ b/javav2/example_code/inspector/src/test/java/InspectorTests.java
@@ -0,0 +1,146 @@
+// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+// SPDX-License-Identifier: Apache-2.0
+
+import com.java.inspector.InspectorScenario;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.java.inspector.HelloInspector;
+import com.java.inspector.InspectorActions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+import org.junit.jupiter.api.TestMethodOrder;
+import software.amazon.awssdk.regions.Region;
+import software.amazon.awssdk.services.inspector2.Inspector2Client;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.util.Collections;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@TestInstance(TestInstance.Lifecycle.PER_METHOD)
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+public class InspectorTests {
+ private static Inspector2Client inspector;
+ private static InspectorActions inspectorActions;
+ private static final Logger logger = LoggerFactory.getLogger(InspectorTests.class);
+ @BeforeAll
+ public static void setUp() {
+ inspector = Inspector2Client.builder()
+ .region(Region.US_EAST_1)
+ .build() ;
+
+ inspectorActions = new InspectorActions();
+ }
+
+ @Test
+ @Tag("IntegrationTest")
+ @Order(1)
+ public void testHelloService() {
+ assertDoesNotThrow(() -> {
+ HelloInspector.checkAccountStatus(inspector);
+ HelloInspector.listRecentFindings(inspector);
+ HelloInspector.showUsageTotals(inspector);
+ });
+ logger.info("Test 1 passed");
+ }
+
+
+ /**
+ * Integration test for InspectorActions Async methods.
+ *
+ * This test validates that all async action methods complete successfully and
+ * return expected values (like filter ARN).
+ *
+ * Note that it will fail the test if any .join() throws a CompletionException.
+ */
+
+ @Test
+ @Tag("IntegrationTest")
+ @Order(2)
+ public void testInspectorActionsIntegration() {
+ assertDoesNotThrow(() -> {
+ int maxResults = 10;
+
+ String filterName = "suppress-low-severity-" + System.currentTimeMillis();
+
+ inspectorActions.getAccountStatusAsync().join();
+
+ inspectorActions.enableInspectorAsync(null).join();
+
+ String allFindings = inspectorActions.listLowSeverityFindingsAsync().join();
+ // Check if any findings were returned
+ if (allFindings == null || allFindings.startsWith("No LOW severity findings")) {
+ logger.info("No LOW severity findings available. Skipping details lookup.");
+ } else {
+ String[] arns = allFindings.split("\\r?\\n");
+ String lastArn = arns[arns.length - 1];
+
+ // Fetch details safely
+ String details = inspectorActions.getFindingDetailsAsync(lastArn).join();
+ logger.info("Details for last LOW severity finding:\n{}", details);
+ }
+
+
+ maxResults = 5;
+ inspectorActions.listCoverageAsync(maxResults).join();
+
+ String filterARN = inspectorActions.createLowSeverityFilterAsync(filterName,"Suppress low severity findings for demo purposes").join();
+
+ // Assert it returned a valid ARN
+ assertNotNull(filterARN, "Filter ARN should not be null");
+ assertFalse(filterARN.isBlank(), "Filter ARN should not be empty");
+
+ inspectorActions.listFiltersAsync(10).join();
+
+ inspectorActions.listUsageTotalsAsync(null, 10).join();
+
+ inspectorActions.listCoverageStatisticsAsync().join();
+
+ inspectorActions.deleteFilterAsync(filterARN).join();
+ });
+
+ logger.info("Test 2 passed");
+ }
+
+
+ @Test
+ @Tag("IntegrationTest")
+ @Order(3)
+ public void testInspectorScenarioEndToEnd() {
+ assertDoesNotThrow(() -> {
+ // The scenario calls scanner.nextLine() repeatedly.
+ // We simulate user input by providing many "c" lines.
+ String simulatedInput = String.join("\n",
+ Collections.nCopies(20, "c")) + "\n";
+
+ InputStream originalIn = System.in;
+ PrintStream originalOut = System.out;
+
+ try {
+ // Redirect System.in to simulated input
+ ByteArrayInputStream testIn = new ByteArrayInputStream(simulatedInput.getBytes());
+ System.setIn(testIn);
+
+ // Capture System.out so logs don’t spam the console
+ System.setOut(new PrintStream(new ByteArrayOutputStream()));
+
+ // Run the scenario
+ InspectorScenario.main(new String[]{});
+
+ } finally {
+ // Restore original I/O streams
+ System.setIn(originalIn);
+ System.setOut(originalOut);
+ }
+ });
+
+ logger.info("Test 3 (Scenario end-to-end) passed");
+ }
+}
\ No newline at end of file
diff --git a/scenarios/basics/inspector/SPECIFICATION.md b/scenarios/basics/inspector/SPECIFICATION.md
index 51eece5c95f..c8fa8a1db0e 100644
--- a/scenarios/basics/inspector/SPECIFICATION.md
+++ b/scenarios/basics/inspector/SPECIFICATION.md
@@ -1,6 +1,9 @@
# Amazon Inspector Specification
-This document contains a draft proposal for an *Amazon Inspector Basics Scenario*, generated by the Code Examples SpecGen AI tool. The specifications describe a potential code example scenario based on research, usage data, service information, and AI-assistance. The following should be reviewed for accuracy and correctness before proceeding on to a final specification.
+This SDK Basics scenario demonstrates how to interact with Amazon Inspector, a basics scenario that showcases AWS services and SDKs. It is primarily intended for the AWS code examples team to use while developing this example in additional languages.
+
+## Resources
+This Basics scenario does not require any additional AWS resources.
### Relevant documentation
@@ -11,79 +14,111 @@ This document contains a draft proposal for an *Amazon Inspector Basics Scenario
### API Actions Used
+* [CreateFilter](https://docs.aws.amazon.com/inspector/v2/APIReference/API_CreateFilter.html)
+
* [Enable](https://docs.aws.amazon.com/inspector/v2/APIReference/API_Enable.html)
+
+* [ListCoverageStatistics](https://docs.aws.amazon.com/inspector/v2/APIReference/API_ListCoverageStatistics.html)
+
+
+* [ListUsageTotals](https://docs.aws.amazon.com/inspector/v2/APIReference/API_ListUsageTotals.html)
+
* [BatchGetAccountStatus](https://docs.aws.amazon.com/inspector/v2/APIReference/API_BatchGetAccountStatus.html)
+
+* [ListFilters](https://docs.aws.amazon.com/inspector/v2/APIReference/API_ListFilters.html)
+
* [ListFindings](https://docs.aws.amazon.com/inspector/v2/APIReference/API_ListFindings.html)
+
* [BatchGetFindingDetails](https://docs.aws.amazon.com/inspector/v2/APIReference/API_BatchGetFindingDetails.html)
+
* [ListCoverage](https://docs.aws.amazon.com/inspector/v2/APIReference/API_ListCoverage.html)
-* [Disable](https://docs.aws.amazon.com/inspector/v2/APIReference/API_Disable.html)
-## Proposed example structure
+* [DeleteFilter](https://docs.aws.amazon.com/inspector/v2/APIReference/API_DeleteFilter.html)
-The output below demonstrates how this example would run for the customer. It includes a Hello service example (included for all services), and the scenario description. The scenario code would also be presented as Action snippets, with a code snippet for each SDK action.
-### Hello
+## Hello Amazon Inspector
-The Hello example is a separate runnable example. - Set up the Inspector service client - Check the current account status for Inspector - Display available scan types and regions
+The Hello example is intended for users not familiar with this service to easily get up and running. It sets up the Inspector service client, checks the current account status for Inspector and displays available scan types.
## Scenario
-#### Setup
+This scenario demonstrates the basic usage of **Amazon Inspector** using a Java program. It focuses on checking account status, enabling Inspector, listing findings, reviewing coverage, and managing filters.
-* Enable Amazon Inspector for the account
-* Verify Inspector is successfully activated
-* Display account status and enabled scan types
+---
-#### Coverage Assessment
+### Setup
-* List coverage statistics for EC2 instances, ECR repositories, and Lambda functions
-* Display resource coverage details
-* Show scanning status for different resource types
+* Check Amazon Inspector account status
+* Enable Inspector for available resource types (if not already enabled)
+* Display account status summary
-#### Findings Management
+---
+
+### Coverage Assessment
+
+* List coverage details for scanned resources
+* Display overall coverage statistics
+* Review scan status for resources (general overview)
+
+---
+
+### Findings Management
* List security findings across all resource types
-* Filter findings by severity level (CRITICAL, HIGH, MEDIUM, LOW)
-* Retrieve detailed information for specific findings
+* Create an example filter to suppress low-severity findings
+* List existing filters
+
+---
-#### Vulnerability Analysis
+### Usage and Costs
-* Display vulnerability details including CVE information
-* Show affected resources and remediation guidance
-* Filter findings by resource type (EC2, ECR, Lambda)
+* Check usage totals and metrics for Inspector
+* Review coverage statistics
-#### Cleanup
+---
-* Optionally disable Inspector scanning (with user confirmation)
-* Display final account status
+### Outcome
+
+By following this scenario, users learn how to:
+
+* Check Inspector account status and configuration
+* Enable Inspector for different resource types
+* List and analyze security findings
+* Monitor scan coverage
+* Create and manage filters
+* Track usage and coverage statistics
## Errors
-SDK Code examples include basic exception handling for each action used. The table below describes an appropriate exception which will be handled in the code for each service action.
-
-|Action |Error |Handling |
-|--- |--- |--- |
-|`Enable` |ValidationException |Validate resource types and account permissions. |
-|`Enable` |AccessDeniedException |Notify user of insufficient permissions and exit. |
-|`BatchGetAccountStatus` |ValidationException |Validate account IDs format. |
-|`BatchGetAccountStatus` |AccessDeniedException |Handle permission errors gracefully. |
-|`ListFindings` |ValidationException |Validate filter criteria and pagination parameters. |
-|`ListFindings` |InternalServerException |Retry operation with exponential backoff. |
-|`BatchGetFindingDetails` |ValidationException |Validate finding ARNs format. |
-|`BatchGetFindingDetails` |AccessDeniedException |Handle access denied for specific findings. |
-|`ListCoverage` |ValidationException |Validate filter and pagination parameters. |
-|`Disable` |ValidationException |Validate resource types for disabling. |
-|`Disable` |ConflictException |Handle cases where Inspector cannot be disabled. |
+The table below describes the exceptions handled in the program for each action.
-## Metadata
+| Action | Exception | Handling |
+|-------------------------------|---------------------------|--------------------------------------------------------------------------|
+| `Enable` | `ValidationException` | Prints a message indicating Inspector may already be enabled. |
+| `listUsageTotals` | `ValidationException` | Validation error listing usage totals.
+| `BatchGetAccountStatus` | `AccessDeniedException` | Prints AWS service error details and rethrows the exception. |
+| `ListFindings` | `ValidationException` | Prints validation error details. |
+| `ListCoverage` | `ValidationException` | Prints validation error details. |
+| `ListCoverageStatistics` | `ValidationException` | Prints validation error details. |
+| `createFilter` | `ValidationException` | Prints validation error details. |
+| `ListFilters` | `ValidationException` | Prints AWS service error details and rethrows the exception. |
+| `deleteFilter` | `ResourceNotFoundException` | Prints AWS service error details and rethrows the exception. |
+| `batchGetFindingDetails` | `ResourceNotFoundException` | Prints AWS service error details and rethrows the exception. |
-|action / scenario |metadata file |metadata key |
-|--- |--- |--- |
-|`Enable` |inspector_metadata.yaml |inspector_Enable |
-|`BatchGetAccountStatus` |inspector_metadata.yaml |inspector_BatchGetAccountStatus |
-|`ListFindings` |inspector_metadata.yaml |inspector_ListFindings |
-|`BatchGetFindingDetails` |inspector_metadata.yaml |inspector_BatchGetFindingDetails |
-|`ListCoverage` |inspector_metadata.yaml |inspector_ListCoverage |
-|`Disable` |inspector_metadata.yaml |inspector_Disable |
-|`Amazon Inspector Basics Scenario` |inspector_metadata.yaml |inspector_Scenario |
+## Metadata
+
+| Action / Scenario | Metadata File | Metadata Key |
+|-----------------------------------------|------------------------|-------------------------------|
+| `Enable` | inspector_metadata.yaml | inspector_EnableInspector |
+| `BatchGetAccountStatus` | inspector_metadata.yaml | inspector_GetAccountStatus |
+| `ListFindings` | inspector_metadata.yaml | inspector_ListFindings |
+| `ListCoverage` | inspector_metadata.yaml | inspector_ListCoverage |
+| `ListCoverageStatistics` | inspector_metadata.yaml | inspector_ListCoverageStatistics |
+| `ListUsageTotals` | inspector_metadata.yaml | inspector_ListUsageTotals |
+| `CreateFilter` | inspector_metadata.yaml | inspector_CreateFilter |
+| `ListFilters` | inspector_metadata.yaml | inspector_ListFilters |
+| `DeleteFilter` | inspector_metadata.yaml | inspector_DeleteFilter` |
+| `batchGetFindingDetails` | inspector_metadata.yaml | inspector_BatchGetFindingDetails |
+| `Amazon Inspector Hello` | inspector_metadata.yaml | inspector_Hello |
+| `Amazon Inspector Basics Scenario` | inspector_metadata.yaml | inspector_Scenario
\ No newline at end of file