Invoke SV scan when solution revisions received 83/5183/1
authorAndrew Gauld <agauld@att.com>
Thu, 5 Sep 2019 18:32:20 +0000 (18:32 +0000)
committerAndrew Gauld <agauld@att.com>
Thu, 5 Sep 2019 18:35:01 +0000 (18:35 +0000)
And fix a few things SONAR started complaining about

Change-Id: Ib99b2b99ded3e4781103613c9493cd829ba58b3f
Issue-ID: ACUMOS-3396
Signed-off-by: Andrew Gauld <agauld@att.com>
12 files changed:
acumos-fgw-client/src/test/java/org/acumos/federation/client/ClientTest.java
docs/config.rst
docs/release-notes.rst
gateway/pom.xml
gateway/src/main/java/org/acumos/federation/gateway/Application.java
gateway/src/main/java/org/acumos/federation/gateway/Clients.java
gateway/src/main/java/org/acumos/federation/gateway/FederationController.java
gateway/src/main/java/org/acumos/federation/gateway/GatewayController.java
gateway/src/main/java/org/acumos/federation/gateway/SubscriptionPoller.java
gateway/src/test/java/org/acumos/federation/gateway/ClientsTest.java
gateway/src/test/java/org/acumos/federation/gateway/FederationControllerTest.java
gateway/src/test/java/org/acumos/federation/gateway/GatewayControllerTest.java

index dd134d4..271780f 100644 (file)
@@ -186,6 +186,7 @@ public class ClientTest {
        @Test
        public void testUpload() throws Exception {
                UploadTest client = new UploadTest();
+               assertNotNull(client);
                (new ClientMocking())
                    .errorOnNoAuth(401, "Unauthorized")
                    .errorOnBadAuth("acumosa", "acumosa", 403, "Forbidden")
index 38178e1..c565778 100644 (file)
@@ -61,7 +61,8 @@ Example (with syntactically valid but completely made up values)::
       "username": "nexususer",
       "password": "nexuspass",
       "nexus.group-id": "myorg"
-    }
+    },
+    "verification.url": "http://securityserver:9999"
   }'
 
 Note that::
@@ -288,6 +289,12 @@ nexus.name-separator
   Separator between components of the path prefix within the Nexus repository.
   The prefix is of the form groupid separator solutionid separator revisionid.
 
+verification.url
+  Required.
+
+  URL for the Acumos security-verification server used to perform security
+  verification scans on solution revisions.
+
 =========================================
 Federation Gateway Certificate Generation
 =========================================
index 515197f..f0028ec 100644 (file)
@@ -25,7 +25,11 @@ The image name is "federation-gateway" and the tag is a version string as shown
 
 Version 2.3.0, 2019-08-09
 -------------------------
-* Java code upgrade to Java 11 (`ACUMOS-3334 <https://jira.acumos.org/browse/ACUMOS-33334>`_)
+* Run SV license scan when a model has been federated (`ACUMOS-3396 <https://jira.acumos.org/browse/ACUMOS-3396>`_)
+  * This adds a new required configuration value, "verification.url" for the
+    security verification service.
+
+* Java code upgrade to Java 11 (`ACUMOS-3334 <https://jira.acumos.org/browse/ACUMOS-3334>`_)
 
 * Update to CDS 2.2.6
 
index 013e63b..ab5565c 100644 (file)
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-security</artifactId>
                </dependency>
+               <dependency>
+                       <groupId>org.acumos.security-verification</groupId>
+                       <artifactId>security-verification-client</artifactId>
+                       <version>0.0.24</version>
+               </dependency>
                <!-- Compile time only dependencies -->
                <dependency>
                        <groupId>org.projectlombok</groupId>
index 101cf85..61d9499 100644 (file)
@@ -155,6 +155,12 @@ public class Application {
                return new DockerConfig();
        }
 
+       @Bean
+       @ConfigurationProperties(prefix="verification")
+       ServiceConfig verificationConfig() {
+               return new ServiceConfig();
+       }
+
        @Bean
        Clients clients() {
                return new Clients();
index bd29c04..aa0a6f6 100644 (file)
@@ -32,6 +32,9 @@ import org.acumos.federation.client.config.ClientConfig;
 import org.acumos.federation.client.ClientBase;
 import org.acumos.federation.client.FederationClient;
 
+import org.acumos.securityverification.service.ISecurityVerificationClientService;
+import org.acumos.securityverification.service.SecurityVerificationClientServiceImpl;
+
 /**
  * Defines all beans used to access outside services.
  *
@@ -66,8 +69,12 @@ public class Clients {
        @Autowired
        private DockerConfig dockerConfig;
 
+       @Autowired
+       private ServiceConfig verificationConfig;
+
        private ICommonDataServiceRestClient cdsClient;
        private NexusClient nexusClient;
+       private ISecurityVerificationClientService svClient;
 
        public FederationClient getFederationClient(String url) {
                /*
@@ -125,4 +132,18 @@ public class Clients {
                        .build()
                    ).build();
        }
+
+       public synchronized ISecurityVerificationClientService getSVClient() {
+               if (svClient == null) {
+                       svClient = new SecurityVerificationClientServiceImpl(
+                           verificationConfig.getUrl(),
+                           cdmsConfig.getUrl(),
+                           cdmsConfig.getUsername(),
+                           cdmsConfig.getPassword(),
+                           nexusConfig.getUrl(),
+                           nexusConfig.getUsername(),
+                           nexusConfig.getPassword());
+               }
+               return svClient;
+       }
 }
index 1110c88..e0bfa1a 100644 (file)
@@ -38,9 +38,9 @@ import org.springframework.http.MediaType;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.CrossOrigin;
 import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.util.UriTemplateHandler;
@@ -142,7 +142,7 @@ public class FederationController {
 
        @Secured(Security.ROLE_PEER)
        @ApiOperation(value = "Invoked by Peer Acumos to get status and self information.", response = MLPPeer.class)
-       @RequestMapping(value = FederationClient.PING_URI, method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+       @GetMapping(value = FederationClient.PING_URI, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
        @ResponseBody
        public JsonResponse<MLPPeer> ping() {
                log.debug("/ping");
@@ -151,7 +151,7 @@ public class FederationController {
 
        @Secured(Security.ROLE_PARTNER)
        @ApiOperation(value = "Invoked by Peer Acumos to get a list of peers from local Acumos Instance .", response = MLPPeer.class, responseContainer = "List")
-       @RequestMapping(value = FederationClient.PEERS_URI, method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+       @GetMapping(value = FederationClient.PEERS_URI, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
        @ResponseBody
        public JsonResponse<List<MLPPeer>> getPeers() {
                log.debug("/peers");
@@ -160,7 +160,7 @@ public class FederationController {
 
        @Secured(Security.ROLE_REGISTER)
        @ApiOperation(value = "Invoked by another Acumos Instance to request federation.", response = MLPPeer.class)
-       @RequestMapping(value = FederationClient.REGISTER_URI, method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+       @PostMapping(value = FederationClient.REGISTER_URI, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
        @ResponseBody
        public JsonResponse<MLPPeer> register() {
                log.debug("/peer/register");
@@ -173,7 +173,7 @@ public class FederationController {
 
        @Secured(Security.ROLE_UNREGISTER)
        @ApiOperation(value = "Invoked by another Acumos Instance to request federation termination.", response = MLPPeer.class)
-       @RequestMapping(value = FederationClient.UNREGISTER_URI, method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+       @PostMapping(value = FederationClient.UNREGISTER_URI, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
        @ResponseBody
        public JsonResponse<MLPPeer> unregister() {
                log.debug("/peer/unregister");
@@ -186,7 +186,7 @@ public class FederationController {
 
        @Secured(Security.ROLE_PEER)
        @ApiOperation(value = "Invoked by Peer Acumos to get a list of visible Catalogs from the local Acumos Instance .", response = MLPCatalog.class, responseContainer = "List")
-       @RequestMapping(value = FederationClient.CATALOGS_URI, method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+       @GetMapping(value = FederationClient.CATALOGS_URI, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
        @ResponseBody
        public JsonResponse<List<MLPCatalog>> getCatalogs() {
                log.debug("/catalogs");
@@ -195,7 +195,7 @@ public class FederationController {
 
        @Secured(Security.ROLE_PEER)
        @ApiOperation(value = "Invoked by Peer Acumos to get a list of Published Solutions from the Catalog of the local Acumos Instance .", response = MLPSolution.class, responseContainer = "List")
-       @RequestMapping(value = FederationClient.SOLUTIONS_URI, method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+       @GetMapping(value = FederationClient.SOLUTIONS_URI, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
        @ResponseBody
        public JsonResponse<List<MLPSolution>> getSolutions(@RequestParam(value="catalogId", required = true) String catalogId) {
                log.debug("/solutions?catalogId={}", catalogId);
@@ -211,7 +211,7 @@ public class FederationController {
 
        @Secured(Security.ROLE_PEER)
        @ApiOperation(value = "Invoked by Peer Acumos to get a list detailed solution information from the Catalog of the local Acumos Instance .", response = MLPSolution.class)
-       @RequestMapping(value = FederationClient.SOLUTION_URI, method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+       @GetMapping(value = FederationClient.SOLUTION_URI, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
        @ResponseBody
        public JsonResponse<MLPSolution> getSolution(@PathVariable("solutionId") String solutionId) {
                log.debug("/solutions/{}", solutionId);
@@ -225,7 +225,7 @@ public class FederationController {
 
        @Secured(Security.ROLE_PEER)
        @ApiOperation(value = "Invoked by Peer Acumos to get a list of Solution Revision from the Catalog of the local Acumos Instance .", response = MLPSolutionRevision.class, responseContainer = "List")
-       @RequestMapping(value = FederationClient.REVISIONS_URI, method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+       @GetMapping(value = FederationClient.REVISIONS_URI, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
        @ResponseBody
        public JsonResponse<List<MLPSolutionRevision>> getRevisions(@PathVariable("solutionId") String solutionId) {
                log.debug("/solutions/{}/revisions", solutionId);
@@ -238,7 +238,7 @@ public class FederationController {
 
        @Secured(Security.ROLE_PEER)
        @ApiOperation(value = "Invoked by peer Acumos to get solution revision details from the local Acumos Instance .", response = MLPSolutionRevision.class)
-       @RequestMapping(value = FederationClient.REVISION_URI, method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+       @GetMapping(value = FederationClient.REVISION_URI, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
        @ResponseBody
        public JsonResponse<MLPSolutionRevision> getRevision(
            @PathVariable("solutionId") String solutionId,
@@ -263,7 +263,7 @@ public class FederationController {
 
        @Secured(Security.ROLE_PEER)
        @ApiOperation(value = "Invoked by Peer Acumos to get a list of solution revision artifacts from the local Acumos Instance .", response = MLPArtifact.class, responseContainer = "List")
-       @RequestMapping(value = FederationClient.ARTIFACTS_URI, method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+       @GetMapping(value = FederationClient.ARTIFACTS_URI, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
        @ResponseBody
        public JsonResponse<List<MLPArtifact>> getArtifacts(
            @PathVariable("solutionId") String solutionId,
@@ -281,7 +281,7 @@ public class FederationController {
 
        @Secured(Security.ROLE_PEER)
        @ApiOperation(value = "Invoked by Peer Acumos to get a list of solution revision public documents from the local Acumos Instance .", response = MLPArtifact.class, responseContainer = "List")
-       @RequestMapping(value = FederationClient.DOCUMENTS_URI, method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+       @GetMapping(value = FederationClient.DOCUMENTS_URI, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
        @ResponseBody
        public JsonResponse<List<MLPDocument>> getDocuments(
            @PathVariable("revisionId") String revisionId,
@@ -299,7 +299,7 @@ public class FederationController {
 
        @Secured(Security.ROLE_PEER)
        @ApiOperation(value = "API to download artifact content", response = Resource.class, code = 200)
-       @RequestMapping(value = FederationClient.ARTIFACT_URI, method = RequestMethod.GET, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
+       @GetMapping(value = FederationClient.ARTIFACT_URI, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
        @ResponseBody
        public Callable<Resource> getArtifactContent(@PathVariable("artifactId") String artifactId) {
                log.debug("/artifacts/{}/content", artifactId);
@@ -311,7 +311,7 @@ public class FederationController {
 
        @Secured(Security.ROLE_PEER)
        @ApiOperation(value = "API to download document content", response = Resource.class, code = 200)
-       @RequestMapping(value = FederationClient.DOCUMENT_URI, method = RequestMethod.GET, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
+       @GetMapping(value = FederationClient.DOCUMENT_URI, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
        @ResponseBody
        public Resource getDocumentContent(@PathVariable("documentId") String documentId) {
                log.debug("/documents/{}/content", documentId);
index ee6ee3d..8a500e8 100644 (file)
@@ -34,9 +34,10 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.MediaType;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.CrossOrigin;
+import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.security.access.annotation.Secured;
@@ -71,7 +72,7 @@ public class GatewayController {
        private SubscriptionPoller poller;
 
        @ApiOperation(value = "Invoked by local Acumos to get a list of catalogs available from a peer Acumos instance .", response = MLPCatalog.class, responseContainer = "List")
-       @RequestMapping(value = FederationClient.CATALOGS_URI, method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+       @GetMapping(value = FederationClient.CATALOGS_URI, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
        @ResponseBody
        public JsonResponse<List<MLPCatalog>> getCatalogs(
            HttpServletResponse response,
@@ -81,7 +82,7 @@ public class GatewayController {
        }
 
        @ApiOperation(value = "Invoked by local Acumos to get a list of solutions available from a peer Acumos instance .", response = MLPSolution.class, responseContainer = "List")
-       @RequestMapping(value = FederationClient.SOLUTIONS_URI, method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+       @GetMapping(value = FederationClient.SOLUTIONS_URI, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
        @ResponseBody
        public JsonResponse<List<MLPSolution>> getSolutions(
            HttpServletResponse response,
@@ -92,7 +93,7 @@ public class GatewayController {
        }
 
        @ApiOperation(value = "Invoked by local Acumos to get detailed solution information from the catalog of a peer acumos Instance.", response = MLPSolution.class)
-       @RequestMapping(value = FederationClient.SOLUTION_URI, method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+       @GetMapping(value = FederationClient.SOLUTION_URI, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
        @ResponseBody
        public JsonResponse<MLPSolution> getSolution(
            HttpServletResponse response,
@@ -103,7 +104,7 @@ public class GatewayController {
        }
 
        @ApiOperation(value = "Invoked by local Acumos to get peers information from remote Acumos peer.", response = MLPPeer.class, responseContainer = "List")
-       @RequestMapping(value = FederationClient.PEERS_URI, method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+       @GetMapping(value = FederationClient.PEERS_URI, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
        @ResponseBody
        public JsonResponse<List<MLPPeer>> getPeers(
            HttpServletResponse response,
@@ -113,7 +114,7 @@ public class GatewayController {
        }
 
        @ApiOperation(value = "Invoked by local Acumos to get peer Acumos status and information.", response = MLPPeer.class)
-       @RequestMapping(value = FederationClient.PING_URI, method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+       @GetMapping(value = FederationClient.PING_URI, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
        @ResponseBody
        public JsonResponse<MLPPeer> ping(
            HttpServletResponse response,
@@ -123,7 +124,7 @@ public class GatewayController {
        }
 
        @ApiOperation(value = "Invoked by local Acumos to register with a remote Acumos peer.", response = MLPPeer.class)
-       @RequestMapping(value = FederationClient.REGISTER_URI, method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+       @PostMapping(value = FederationClient.REGISTER_URI, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
        @ResponseBody
        public JsonResponse<MLPPeer> register(
            HttpServletResponse response,
@@ -133,7 +134,7 @@ public class GatewayController {
        }
 
        @ApiOperation(value = "Invoked by other Acumos components in order to trigger subscription execution")
-       @RequestMapping(value = GatewayClient.SUBSCRIPTION_URI, method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
+       @PostMapping(value = GatewayClient.SUBSCRIPTION_URI, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
        @ResponseBody
        public JsonResponse<Void> triggerPeerSubscription(
            HttpServletResponse response,
index a18c7a1..bd47cdd 100644 (file)
@@ -216,6 +216,9 @@ public class SubscriptionPoller {
                        if (changed && !isnew) {
                                catalogService.updateRevision(pRev);
                        }
+                       if (changed) {
+                               new Thread(() -> { try {clients.getSVClient().securityVerificationScan(solutionId, revisionId, "created", userId); } catch (Exception e) { log.error("SV scan failure on revision " + revisionId, e); }}).start();
+                       }
                        return changed;
                }
 
index 28df0f0..bec7e08 100644 (file)
@@ -46,7 +46,8 @@ import org.springframework.test.context.junit4.SpringRunner;
        "nexus.name-separator=,",
        "nexus.url=http://nexus.example.org",
        "docker.host=tcp://localhost:999",
-       "cdms.client.url=http://cdms.example.org"
+       "cdms.client.url=http://cdms.example.org",
+       "verification.url=http://svserver.example.org"
     }
 )
 public class ClientsTest {
@@ -72,5 +73,6 @@ public class ClientsTest {
                assertEquals(clients.getCDSClient(), clients.getCDSClient());
                assertEquals(clients.getNexusClient(), clients.getNexusClient());
                assertNotNull(clients.getDockerClient());
+               assertEquals(clients.getSVClient(), clients.getSVClient());
        }
 }
index 6b0793d..708b205 100644 (file)
@@ -309,6 +309,7 @@ public class FederationControllerTest {
        @Test
        public void testSwagger() throws Exception {
                RawAnonClient rac = new RawAnonClient("https://localhost:" + port);
+               assertNotNull(rac);
                rac.get("/swagger-ui.html");
                rac.get("/v2/api-docs");
        }
index 9328417..08788f2 100644 (file)
@@ -31,10 +31,10 @@ import org.junit.Test;
 import org.junit.Before;
 import org.junit.runner.RunWith;
 
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 import static org.mockito.Mockito.any;
 
-
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.web.server.LocalServerPort;
 import org.springframework.boot.test.context.SpringBootTest;
@@ -50,6 +50,8 @@ import org.springframework.web.client.HttpClientErrorException.NotFound;
 import org.acumos.cds.client.ICommonDataServiceRestClient;
 import org.acumos.cds.client.CommonDataServiceRestClientImpl;
 
+import org.acumos.securityverification.service.ISecurityVerificationClientService;
+
 import org.acumos.federation.client.FederationClient;
 import org.acumos.federation.client.GatewayClient;
 import org.acumos.federation.client.ClientBase;
@@ -208,6 +210,9 @@ public class GatewayControllerTest {
 
                docker = new SimulatedDockerClient();
                when(clients.getDockerClient()).thenReturn(docker.getClient());
+
+               ISecurityVerificationClientService sv = mock(ISecurityVerificationClientService.class);
+               when (clients.getSVClient()).thenReturn(sv);
        }
 
        @Test
@@ -277,6 +282,7 @@ public class GatewayControllerTest {
        @Test
        public void testSwagger() throws Exception {
                RawAnonClient rac = new RawAnonClient("https://localhost:" + port);
+               assertNotNull(rac);
                rac.get("/swagger-ui.html");
                rac.get("/v2/api-docs");
        }