diff --git a/src/main/java/org/eclipsefoundation/git/eca/helper/CommitHelper.java b/src/main/java/org/eclipsefoundation/git/eca/helper/CommitHelper.java
index eaa36924daf54e8bf40702963e0d780641b970ea..64b0c77f84da414266b36cd729cc8df8d80d2a4f 100644
--- a/src/main/java/org/eclipsefoundation/git/eca/helper/CommitHelper.java
+++ b/src/main/java/org/eclipsefoundation/git/eca/helper/CommitHelper.java
@@ -11,17 +11,22 @@
 **********************************************************************/
 package org.eclipsefoundation.git.eca.helper;
 
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
 import java.util.List;
 import java.util.stream.Collectors;
 
 import javax.ws.rs.core.MultivaluedMap;
 
+import org.eclipsefoundation.core.exception.ApplicationException;
 import org.eclipsefoundation.efservices.api.models.Project;
 import org.eclipsefoundation.git.eca.model.Commit;
 import org.eclipsefoundation.git.eca.model.ValidationRequest;
 import org.eclipsefoundation.git.eca.namespace.GitEcaParameterNames;
 import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
 
+import io.undertow.util.HexConverter;
+
 /**
  * Contains helpers for processing commits.
  *
@@ -63,8 +68,7 @@ public class CommitHelper {
                 req.getRepoUrl().toString());
     }
 
-    public static MultivaluedMap<String, String> getCommitParams(List<String> commitShas, String projectId,
-            String repoUrl) {
+    public static MultivaluedMap<String, String> getCommitParams(List<String> commitShas, String projectId, String repoUrl) {
         MultivaluedMap<String, String> params = new MultivaluedMapImpl<>();
         params.put(GitEcaParameterNames.SHAS_RAW, commitShas);
         params.add(GitEcaParameterNames.REPO_URL_RAW, repoUrl);
@@ -75,8 +79,27 @@ public class CommitHelper {
     }
 
     /**
-     * Centralized way of retrieving a checked project ID from a project for use
-     * when interacting with commits and commit data.
+     * Generates a request fingerprint for looking up requests that have already been processed in the past. Collision here
+     * is extremely unlikely, and low risk on the change it does. For that reason, a more secure but heavier hashing alg.
+     * wasn't chosen.
+     * 
+     * @param req the request to generate a fingerprint for
+     * @return the fingerprint for the request
+     */
+    public static String generateRequestHash(ValidationRequest req) {
+        StringBuilder sb = new StringBuilder();
+        sb.append(req.getRepoUrl());
+        req.getCommits().forEach(c -> sb.append(c.getHash()));
+        try {
+            return HexConverter.convertToHexString(MessageDigest.getInstance("MD5").digest(sb.toString().getBytes()));
+        } catch (NoSuchAlgorithmException e) {
+            throw new ApplicationException("Error while encoding request fingerprint - couldn't find MD5 algorithm.", e);
+        }
+    }
+
+    /**
+     * Centralized way of retrieving a checked project ID from a project for use when interacting with commits and commit
+     * data.
      * 
      * @param p the current project to attempt to retrieve an ID from
      * @return the project ID or the given default (empty string).
diff --git a/src/main/java/org/eclipsefoundation/git/eca/helper/GithubValidationHelper.java b/src/main/java/org/eclipsefoundation/git/eca/helper/GithubValidationHelper.java
index 58f9f2a2bac2bd6a3ed0bcb94fa1024738e2c1cb..f5ec3697211aed0b29a79da6e47d7a3ec328b15a 100644
--- a/src/main/java/org/eclipsefoundation/git/eca/helper/GithubValidationHelper.java
+++ b/src/main/java/org/eclipsefoundation/git/eca/helper/GithubValidationHelper.java
@@ -52,6 +52,7 @@ import org.eclipsefoundation.git.eca.namespace.GithubCommitStatuses;
 import org.eclipsefoundation.git.eca.namespace.ProviderType;
 import org.eclipsefoundation.git.eca.service.GithubApplicationService;
 import org.eclipsefoundation.git.eca.service.ValidationService;
+import org.eclipsefoundation.git.eca.service.ValidationStatusService;
 import org.eclipsefoundation.persistence.dao.PersistenceDao;
 import org.eclipsefoundation.persistence.model.RDBMSQuery;
 import org.eclipsefoundation.persistence.service.FilterService;
@@ -87,6 +88,8 @@ public class GithubValidationHelper {
     @Inject
     ValidationService validation;
     @Inject
+    ValidationStatusService validationStatus;
+    @Inject
     GithubApplicationService ghAppService;
 
     @RestClient
@@ -136,7 +139,7 @@ public class GithubValidationHelper {
         }
 
         // get the commit status of commits to use for checking historic validation
-        List<CommitValidationStatus> statuses = validation.getHistoricValidationStatusByShas(wrapper, commitShas);
+        List<CommitValidationStatus> statuses = validationStatus.getHistoricValidationStatusByShas(wrapper, commitShas);
         if (!"open".equalsIgnoreCase(prResponse.get().getState()) && statuses.isEmpty()) {
             throw new BadRequestException("Cannot find validation history for current non-open PR, cannot provide validation status");
         }
diff --git a/src/main/java/org/eclipsefoundation/git/eca/namespace/GitEcaParameterNames.java b/src/main/java/org/eclipsefoundation/git/eca/namespace/GitEcaParameterNames.java
index cbfaa0ee2926ae4a6d13ae3b6cc4dd40d7cb0ad9..70a657c1a48e4b7e87957692b2477222f53f2565 100644
--- a/src/main/java/org/eclipsefoundation/git/eca/namespace/GitEcaParameterNames.java
+++ b/src/main/java/org/eclipsefoundation/git/eca/namespace/GitEcaParameterNames.java
@@ -35,7 +35,7 @@ public final class GitEcaParameterNames implements UrlParameterNamespace {
     public static final String STATUS_DELETED_RAW = "deleted";
     public static final String SINCE_RAW = "since";
     public static final String UNTIL_RAW = "until";
-    public static final String REPOSITORY_FULL_NAME_RAW = "repository_full_name";
+    public static final String REPOSITORY_FULL_NAME_RAW = "repo_full_name";
     public static final String INSTALLATION_ID_RAW = "installation_id";
     public static final String PULL_REQUEST_NUMBER_RAW = "pull_request_number";
     public static final String USER_MAIL_RAW = "user_mail";
diff --git a/src/main/java/org/eclipsefoundation/git/eca/resource/GithubWebhooksResource.java b/src/main/java/org/eclipsefoundation/git/eca/resource/GithubWebhooksResource.java
index c7a6e176c5d50e0ddff70bb7ab8b5861a8aac191..14a33db9090e7f94dc2b1b951f4bb423a96ed408 100644
--- a/src/main/java/org/eclipsefoundation/git/eca/resource/GithubWebhooksResource.java
+++ b/src/main/java/org/eclipsefoundation/git/eca/resource/GithubWebhooksResource.java
@@ -18,11 +18,14 @@ import java.util.Optional;
 import javax.inject.Inject;
 import javax.ws.rs.BadRequestException;
 import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
 import javax.ws.rs.NotFoundException;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.ServerErrorException;
+import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
 import org.apache.http.HttpStatus;
@@ -100,6 +103,13 @@ public class GithubWebhooksResource extends GithubAdjacentResource {
         return Response.ok().build();
     }
 
+    @GET
+    @Path("installations")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response getManagedInstallations() {
+        return Response.ok(ghAppService.getManagedInstallations()).build();
+    }
+
     /**
      * Endpoint for triggering revalidation of a past request. Uses the fingerprint hash to lookup the unique request and to
      * rebuild the request and revalidate if it exists.
diff --git a/src/main/java/org/eclipsefoundation/git/eca/resource/StatusResource.java b/src/main/java/org/eclipsefoundation/git/eca/resource/StatusResource.java
index aeef62979e8229cbbb52fdce5d5b89de391eeb17..0db2c74dd31461b8f4a43296e1ae9a4dac87431a 100644
--- a/src/main/java/org/eclipsefoundation/git/eca/resource/StatusResource.java
+++ b/src/main/java/org/eclipsefoundation/git/eca/resource/StatusResource.java
@@ -15,6 +15,7 @@ import java.util.List;
 import java.util.stream.Collectors;
 
 import javax.inject.Inject;
+import javax.ws.rs.BadRequestException;
 import javax.ws.rs.GET;
 import javax.ws.rs.NotFoundException;
 import javax.ws.rs.Path;
@@ -23,13 +24,18 @@ import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
+import org.apache.commons.lang3.StringUtils;
 import org.eclipsefoundation.efservices.api.models.Project;
 import org.eclipsefoundation.git.eca.dto.CommitValidationStatus;
 import org.eclipsefoundation.git.eca.helper.GithubValidationHelper;
 import org.eclipsefoundation.git.eca.helper.ProjectHelper;
+import org.eclipsefoundation.git.eca.model.Commit;
+import org.eclipsefoundation.git.eca.model.ValidationRequest;
 import org.eclipsefoundation.git.eca.model.ValidationResponse;
+import org.eclipsefoundation.git.eca.namespace.ProviderType;
 import org.eclipsefoundation.git.eca.service.GithubApplicationService;
 import org.eclipsefoundation.git.eca.service.ValidationService;
+import org.eclipsefoundation.git.eca.service.ValidationStatusService;
 
 import io.quarkus.qute.Location;
 import io.quarkus.qute.Template;
@@ -47,6 +53,8 @@ public class StatusResource extends GithubAdjacentResource {
     GithubApplicationService ghAppService;
     @Inject
     ValidationService validation;
+    @Inject
+    ValidationStatusService validationStatus;
 
     @Inject
     GithubValidationHelper validationHelper;
@@ -66,7 +74,7 @@ public class StatusResource extends GithubAdjacentResource {
     @GET
     @Path("{fingerprint}")
     public Response getCommitValidation(@PathParam("fingerprint") String fingerprint) {
-        return Response.ok(validation.getHistoricValidationStatus(wrapper, fingerprint)).build();
+        return Response.ok(validationStatus.getHistoricValidationStatus(wrapper, fingerprint)).build();
     }
 
     /**
@@ -80,7 +88,7 @@ public class StatusResource extends GithubAdjacentResource {
     @Produces(MediaType.TEXT_HTML)
     @Path("{fingerprint}/ui")
     public Response getCommitValidationUI(@PathParam("fingerprint") String fingerprint) {
-        List<CommitValidationStatus> statuses = validation.getHistoricValidationStatus(wrapper, fingerprint);
+        List<CommitValidationStatus> statuses = validationStatus.getHistoricValidationStatus(wrapper, fingerprint);
         if (statuses.isEmpty()) {
             throw new NotFoundException(String.format("Fingerprint '%s' not found", fingerprint));
         }
@@ -112,24 +120,45 @@ public class StatusResource extends GithubAdjacentResource {
     @Path("gh/{org}/{repoName}/{prNo}")
     public Response getCommitValidationForGithub(@PathParam("org") String org, @PathParam("repoName") String repoName,
             @PathParam("prNo") Integer prNo) {
-        // run the validation for the current request
-        ValidationResponse r = validationHelper.validateIncomingRequest(wrapper, org, repoName, prNo);
+        String repoFullName = org + '/' + repoName;
+        // check that the passed repo has a valid installation
+        String installationId = ghAppService.getInstallationForRepo(repoFullName);
+        if (StringUtils.isBlank(installationId)) {
+            throw new BadRequestException("Repo " + repoFullName + " requested, but does not have visible installation, returning");
+        }
 
-        // retrieve the status of the commits to display on the status page
-        List<CommitValidationStatus> statuses = validation
-                .getHistoricValidationStatusByShas(wrapper, r.getCommits().keySet().stream().collect(Collectors.toList()));
-        // get projects for use in status UI
-        List<Project> ps = projects.retrieveProjectsForRepoURL(statuses.get(0).getRepoUrl(), statuses.get(0).getProvider());
+        // generate the URL used to retrieve valid projects
+        String repoUrl = GithubValidationHelper.getRepoUrl(org, repoName);
+
+        // get the data about the current request, and check that we have some validation statuses
+        ValidationRequest req = validationHelper.generateRequest(installationId, repoFullName, prNo, repoUrl);
+        List<CommitValidationStatus> statuses = validationStatus
+                .getHistoricValidationStatusByShas(wrapper, req.getCommits().stream().map(Commit::getHash).collect(Collectors.toList()));
+        // check if we have any data, and if there is none, attempt to validate the request information
+        if (statuses.isEmpty()) {
+            // run the validation for the current request
+            ValidationResponse r = validationHelper.validateIncomingRequest(wrapper, org, repoName, prNo);
+            if (r == null) {
+                throw new BadRequestException("Cannot validate request for " + repoFullName + "#" + prNo + " as it is already closed");
+            }
+
+            // retrieve the status of the commits to display on the status page
+            statuses = validationStatus
+                    .getHistoricValidationStatusByShas(wrapper, r.getCommits().keySet().stream().collect(Collectors.toList()));
+        }
+
+        // get projects for use in queries + UI
+        List<Project> ps = projects.retrieveProjectsForRepoURL(repoUrl, ProviderType.GITHUB);
         // render and return the status UI
         return Response
                 .ok()
                 .entity(statusUiTemplate
                         .data("statuses", statuses)
                         .data("pullRequestNumber", prNo)
-                        .data("fullRepoName", org + '/' + repoName)
+                        .data("fullRepoName", repoFullName)
                         .data("project", ps.isEmpty() ? null : ps.get(0))
-                        .data("repoUrl", GithubValidationHelper.getRepoUrl(org, repoName))
-                        .data("installationId", ghAppService.getInstallationForRepo(org + '/' + repoName))
+                        .data("repoUrl", repoUrl)
+                        .data("installationId", ghAppService.getInstallationForRepo(repoFullName))
                         .render())
                 .build();
     }
diff --git a/src/main/java/org/eclipsefoundation/git/eca/service/GithubApplicationService.java b/src/main/java/org/eclipsefoundation/git/eca/service/GithubApplicationService.java
index 3a36f46cafccdc234ec3197048ece07b7cf86ec9..4b6cafab702e0c31e24762399649287b11c3e3a5 100644
--- a/src/main/java/org/eclipsefoundation/git/eca/service/GithubApplicationService.java
+++ b/src/main/java/org/eclipsefoundation/git/eca/service/GithubApplicationService.java
@@ -13,6 +13,8 @@ package org.eclipsefoundation.git.eca.service;
 
 import java.util.Optional;
 
+import javax.ws.rs.core.MultivaluedMap;
+
 import org.eclipsefoundation.git.eca.api.models.GithubWebhookRequest.PullRequest;
 
 /**
@@ -23,6 +25,13 @@ import org.eclipsefoundation.git.eca.api.models.GithubWebhookRequest.PullRequest
  */
 public interface GithubApplicationService {
 
+    /**
+     * Retrieve safe map of all installations that are managed by this instance of the Eclispe ECA app.
+     * 
+     * @return map containing installation IDs mapped to the list of repos they support for the current app
+     */
+    MultivaluedMap<String, String> getManagedInstallations();
+
     /**
      * Retrieves the installation ID for the ECA app on the given repo if it exists.
      * 
diff --git a/src/main/java/org/eclipsefoundation/git/eca/service/ValidationService.java b/src/main/java/org/eclipsefoundation/git/eca/service/ValidationService.java
index ff23076451d0c2ec7e6eddf2cdfe369825adf06a..dc75ec9a3f32ec8cee279c8adba780338f12bec2 100644
--- a/src/main/java/org/eclipsefoundation/git/eca/service/ValidationService.java
+++ b/src/main/java/org/eclipsefoundation/git/eca/service/ValidationService.java
@@ -11,21 +11,12 @@
 **********************************************************************/
 package org.eclipsefoundation.git.eca.service;
 
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.List;
-
-import org.eclipsefoundation.core.exception.ApplicationException;
 import org.eclipsefoundation.core.model.RequestWrapper;
-import org.eclipsefoundation.efservices.api.models.Project;
-import org.eclipsefoundation.git.eca.dto.CommitValidationStatus;
 import org.eclipsefoundation.git.eca.model.ValidationRequest;
 import org.eclipsefoundation.git.eca.model.ValidationResponse;
 
-import io.undertow.util.HexConverter;
-
 /**
- * Service containing logic for validating commits, and retrieving/updating previous validation statuses.
+ * Service containing logic for validating commits.
  * 
  * @author Martin Lowe
  *
@@ -42,64 +33,4 @@ public interface ValidationService {
      */
     public ValidationResponse validateIncomingRequest(ValidationRequest req, RequestWrapper wrapper);
 
-    /**
-     * Retrieves a set of validation status objects given the validation request fingerprint.
-     * 
-     * @param wrapper current request wrapper object
-     * @param fingerprint the validation request fingerprint
-     * @return the list of historic validation status objects, or an empty list.
-     */
-    public List<CommitValidationStatus> getHistoricValidationStatus(RequestWrapper wrapper, String fingerprint);
-
-    /**
-     * Retrieves a set of validation status objects given the target shas.
-     * 
-     * @param wrapper current request wrapper object
-     * @param shas list of shas to use when fetching historic commit statuses
-     * @return the list of historic validation status objects, or an empty list.
-     */
-    public List<CommitValidationStatus> getHistoricValidationStatusByShas(RequestWrapper wrapper, List<String> shas);
-
-    /**
-     * Retrieves a set of commit validation status objects given a validation request and target project.
-     * 
-     * @param wrapper current request wrapper object
-     * @param req the current validation request
-     * @param projectId the project targeted by the validation request
-     * @return the list of existing validation status objects for the validation request, or an empty list.
-     */
-    public List<CommitValidationStatus> getRequestCommitValidationStatus(RequestWrapper wrapper, ValidationRequest req, String projectId);
-
-    /**
-     * Updates or creates validation status objects for the commits validated as part of the current validation request.
-     * Uses information from both the original request and the final response to generate details to be preserved in commit
-     * status objects.
-     * 
-     * @param wrapper current request wrapper object
-     * @param r the final validation response
-     * @param req the current validation request
-     * @param statuses list of existing commit validation objects to update
-     * @param p the project targeted by the validation request.
-     */
-    public void updateCommitValidationStatus(RequestWrapper wrapper, ValidationResponse r, ValidationRequest req,
-            List<CommitValidationStatus> statuses, Project p);
-
-    /**
-     * Generates a request fingerprint for looking up requests that have already been processed in the past. Collision here
-     * is extremely unlikely, and low risk on the change it does. For that reason, a more secure but heavier hashing alg.
-     * wasn't chosen.
-     * 
-     * @param req the request to generate a fingerprint for
-     * @return the fingerprint for the request
-     */
-    default String generateRequestHash(ValidationRequest req) {
-        StringBuilder sb = new StringBuilder();
-        sb.append(req.getRepoUrl());
-        req.getCommits().forEach(c -> sb.append(c.getHash()));
-        try {
-            return HexConverter.convertToHexString(MessageDigest.getInstance("MD5").digest(sb.toString().getBytes()));
-        } catch (NoSuchAlgorithmException e) {
-            throw new ApplicationException("Error while encoding request fingerprint - couldn't find MD5 algorithm.", e);
-        }
-    }
 }
diff --git a/src/main/java/org/eclipsefoundation/git/eca/service/ValidationStatusService.java b/src/main/java/org/eclipsefoundation/git/eca/service/ValidationStatusService.java
new file mode 100644
index 0000000000000000000000000000000000000000..193f5455d2a6f9268fd9dca322b84b04f1047cc9
--- /dev/null
+++ b/src/main/java/org/eclipsefoundation/git/eca/service/ValidationStatusService.java
@@ -0,0 +1,69 @@
+/**
+ * Copyright (c) 2023 Eclipse Foundation
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * Author: Martin Lowe <martin.lowe@eclipse-foundation.org>
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.eclipsefoundation.git.eca.service;
+
+import java.util.List;
+
+import org.eclipsefoundation.core.model.RequestWrapper;
+import org.eclipsefoundation.efservices.api.models.Project;
+import org.eclipsefoundation.git.eca.dto.CommitValidationStatus;
+import org.eclipsefoundation.git.eca.model.ValidationRequest;
+import org.eclipsefoundation.git.eca.model.ValidationResponse;
+
+/**
+ * Interface for retrieving/updating validation statuses.
+ */
+public interface ValidationStatusService {
+
+    /**
+     * Retrieves a set of validation status objects given the validation request fingerprint.
+     * 
+     * @param wrapper current request wrapper object
+     * @param fingerprint the validation request fingerprint
+     * @return the list of historic validation status objects, or an empty list.
+     */
+    public List<CommitValidationStatus> getHistoricValidationStatus(RequestWrapper wrapper, String fingerprint);
+
+    /**
+     * Retrieves a set of validation status objects given the target shas.
+     * 
+     * @param wrapper current request wrapper object
+     * @param shas list of shas to use when fetching historic commit statuses
+     * @return the list of historic validation status objects, or an empty list.
+     */
+    public List<CommitValidationStatus> getHistoricValidationStatusByShas(RequestWrapper wrapper, List<String> shas);
+
+    /**
+     * Retrieves a set of commit validation status objects given a validation request and target project.
+     * 
+     * @param wrapper current request wrapper object
+     * @param req the current validation request
+     * @param projectId the project targeted by the validation request
+     * @return the list of existing validation status objects for the validation request, or an empty list.
+     */
+    public List<CommitValidationStatus> getRequestCommitValidationStatus(RequestWrapper wrapper, ValidationRequest req, String projectId);
+
+    /**
+     * Updates or creates validation status objects for the commits validated as part of the current validation request.
+     * Uses information from both the original request and the final response to generate details to be preserved in commit
+     * status objects.
+     * 
+     * @param wrapper current request wrapper object
+     * @param r the final validation response
+     * @param req the current validation request
+     * @param statuses list of existing commit validation objects to update
+     * @param p the project targeted by the validation request.
+     */
+    public void updateCommitValidationStatus(RequestWrapper wrapper, ValidationResponse r, ValidationRequest req,
+            List<CommitValidationStatus> statuses, Project p);
+
+}
diff --git a/src/main/java/org/eclipsefoundation/git/eca/service/impl/DefaultGithubApplicationService.java b/src/main/java/org/eclipsefoundation/git/eca/service/impl/DefaultGithubApplicationService.java
index 1b374c05f6b817b63b65a9efa8a2dfa6dafe94ee..d1f04c3356fc1c5ca566720395a6b17ae1bcb1cf 100644
--- a/src/main/java/org/eclipsefoundation/git/eca/service/impl/DefaultGithubApplicationService.java
+++ b/src/main/java/org/eclipsefoundation/git/eca/service/impl/DefaultGithubApplicationService.java
@@ -12,6 +12,7 @@
 package org.eclipsefoundation.git.eca.service.impl;
 
 import java.time.Duration;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Optional;
 import java.util.concurrent.TimeUnit;
@@ -53,8 +54,8 @@ public class DefaultGithubApplicationService implements GithubApplicationService
 
     // cache kept small as there should only ever really be 1 entry, but room added for safety
     private static final Integer MAX_CACHE_SIZE = 10;
-    private static final Long INSTALL_REPO_FETCH_MAX_TIMEOUT = 10l;
-    
+    private static final Long INSTALL_REPO_FETCH_MAX_TIMEOUT = 15l;
+
     @ConfigProperty(name = "eclipse.github.default-api-version", defaultValue = "2022-11-28")
     String apiVersion;
 
@@ -85,12 +86,27 @@ public class DefaultGithubApplicationService implements GithubApplicationService
         getAllInstallRepos();
     }
 
+    @Override
+    public MultivaluedMap<String, String> getManagedInstallations() {
+        // create a deep copy of the map to protect from modifications and return it
+        MultivaluedMap<String, String> mapClone = new MultivaluedMapImpl<>();
+        getAllInstallRepos().entrySet().stream().forEach(e -> mapClone.put(e.getKey(), new ArrayList<>(e.getValue())));
+        return mapClone;
+    }
+
     @Override
     public String getInstallationForRepo(String repoFullName) {
         MultivaluedMap<String, String> map = getAllInstallRepos();
         return map.keySet().stream().filter(k -> map.get(k).contains(repoFullName)).findFirst().orElse(null);
     }
 
+    @Override
+    public Optional<PullRequest> getPullRequest(String installationId, String repoFullName, Integer pullRequest) {
+        return cache
+                .get(repoFullName, new MultivaluedMapImpl<>(), PullRequest.class,
+                        () -> gh.getPullRequest(jwt.getGhBearerString(installationId), apiVersion, repoFullName, pullRequest));
+    }
+
     private MultivaluedMap<String, String> getAllInstallRepos() {
         try {
             return this.installationRepositoriesCache.get("all").get(INSTALL_REPO_FETCH_MAX_TIMEOUT, TimeUnit.SECONDS);
@@ -105,13 +121,6 @@ public class DefaultGithubApplicationService implements GithubApplicationService
         return new MultivaluedMapImpl<>();
     }
 
-    @Override
-    public Optional<PullRequest> getPullRequest(String installationId, String repoFullName, Integer pullRequest) {
-        return cache
-                .get(repoFullName, new MultivaluedMapImpl<>(), PullRequest.class,
-                        () -> gh.getPullRequest(jwt.getGhBearerString(installationId), apiVersion, repoFullName, pullRequest));
-    }
-
     /**
      * Retrieves a fresh copy of installation repositories, mapped by installation ID to associated full repo names.
      * 
diff --git a/src/main/java/org/eclipsefoundation/git/eca/service/impl/DefaultValidationService.java b/src/main/java/org/eclipsefoundation/git/eca/service/impl/DefaultValidationService.java
index 6e548ae0f9f234b8abbfeb3fe0c53af63d636a29..e331e25554dcf0dfd201df3eb150b21d54ddfbbf 100644
--- a/src/main/java/org/eclipsefoundation/git/eca/service/impl/DefaultValidationService.java
+++ b/src/main/java/org/eclipsefoundation/git/eca/service/impl/DefaultValidationService.java
@@ -11,45 +11,34 @@
 **********************************************************************/
 package org.eclipsefoundation.git.eca.service.impl;
 
-import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
-import java.util.Map.Entry;
 import java.util.Optional;
-import java.util.stream.Collectors;
 
 import javax.enterprise.context.ApplicationScoped;
 import javax.inject.Inject;
 import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
 
 import org.apache.commons.lang3.StringUtils;
-import org.eclipsefoundation.core.helper.DateTimeHelper;
 import org.eclipsefoundation.core.model.RequestWrapper;
 import org.eclipsefoundation.core.service.CachingService;
 import org.eclipsefoundation.efservices.api.models.Project;
 import org.eclipsefoundation.git.eca.api.models.EclipseUser;
 import org.eclipsefoundation.git.eca.config.MailValidationConfig;
-import org.eclipsefoundation.git.eca.dto.CommitValidationMessage;
 import org.eclipsefoundation.git.eca.dto.CommitValidationStatus;
-import org.eclipsefoundation.git.eca.dto.CommitValidationStatusGrouping;
 import org.eclipsefoundation.git.eca.helper.CommitHelper;
 import org.eclipsefoundation.git.eca.helper.ProjectHelper;
 import org.eclipsefoundation.git.eca.model.Commit;
-import org.eclipsefoundation.git.eca.model.CommitStatus;
 import org.eclipsefoundation.git.eca.model.GitUser;
 import org.eclipsefoundation.git.eca.model.ValidationRequest;
 import org.eclipsefoundation.git.eca.model.ValidationResponse;
 import org.eclipsefoundation.git.eca.namespace.APIStatusCode;
-import org.eclipsefoundation.git.eca.namespace.GitEcaParameterNames;
 import org.eclipsefoundation.git.eca.service.UserService;
 import org.eclipsefoundation.git.eca.service.ValidationService;
+import org.eclipsefoundation.git.eca.service.ValidationStatusService;
 import org.eclipsefoundation.persistence.dao.PersistenceDao;
-import org.eclipsefoundation.persistence.model.RDBMSQuery;
 import org.eclipsefoundation.persistence.service.FilterService;
-import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -71,6 +60,8 @@ public class DefaultValidationService implements ValidationService {
     ProjectHelper projects;
     @Inject
     UserService users;
+    @Inject
+    ValidationStatusService statusService;
 
     @Inject
     CachingService cache;
@@ -89,7 +80,7 @@ public class DefaultValidationService implements ValidationService {
                 .builder()
                 .setStrictMode(Boolean.TRUE.equals(req.getStrictMode()))
                 .setTrackedProject(!filteredProjects.isEmpty())
-                .setFingerprint(generateRequestHash(req))
+                .setFingerprint(CommitHelper.generateRequestHash(req))
                 .build();
         // check to make sure commits are valid
         if (req.getCommits().stream().anyMatch(c -> !CommitHelper.validateCommit(c))) {
@@ -105,8 +96,8 @@ public class DefaultValidationService implements ValidationService {
         }
 
         // get previous validation status messages
-        List<CommitValidationStatus> statuses = getRequestCommitValidationStatus(wrapper, req,
-                filteredProjects.isEmpty() ? null : filteredProjects.get(0).getProjectId());
+        List<CommitValidationStatus> statuses = statusService
+                .getRequestCommitValidationStatus(wrapper, req, filteredProjects.isEmpty() ? null : filteredProjects.get(0).getProjectId());
 
         req.getCommits().stream().forEach(c -> {
             // get the current status if present
@@ -119,138 +110,10 @@ public class DefaultValidationService implements ValidationService {
             // process the current commit
             processCommit(c, r, filteredProjects);
         });
-        updateCommitValidationStatus(wrapper, r, req, statuses, filteredProjects.isEmpty() ? null : filteredProjects.get(0));
+        statusService.updateCommitValidationStatus(wrapper, r, req, statuses, filteredProjects.isEmpty() ? null : filteredProjects.get(0));
         return r;
     }
 
-    @Override
-    public List<CommitValidationStatus> getHistoricValidationStatus(RequestWrapper wrapper, String fingerprint) {
-        if (StringUtils.isAllBlank(fingerprint)) {
-            return Collections.emptyList();
-        }
-        MultivaluedMap<String, String> params = new MultivaluedMapImpl<>();
-        params.add(GitEcaParameterNames.FINGERPRINT_RAW, fingerprint);
-        RDBMSQuery<CommitValidationStatusGrouping> q = new RDBMSQuery<>(wrapper, filters.get(CommitValidationStatusGrouping.class), params);
-        // set use limit to false to collect all data in one request
-        q.setUseLimit(false);
-        return dao.get(q).stream().map(statusGrouping -> statusGrouping.getCompositeId().getCommit()).collect(Collectors.toList());
-    }
-
-    @Override
-    public List<CommitValidationStatus> getHistoricValidationStatusByShas(RequestWrapper wrapper, List<String> shas) {
-        if (shas == null || shas.isEmpty()) {
-            return Collections.emptyList();
-        }
-        MultivaluedMap<String, String> params = new MultivaluedMapImpl<>();
-        params.put(GitEcaParameterNames.SHAS_RAW, shas);
-        RDBMSQuery<CommitValidationStatus> q = new RDBMSQuery<>(wrapper, filters.get(CommitValidationStatus.class), params);
-        // set use limit to false to collect all data in one request
-        q.setUseLimit(false);
-        return dao.get(q);
-    }
-
-    @Override
-    public List<CommitValidationStatus> getRequestCommitValidationStatus(RequestWrapper wrapper, ValidationRequest req, String projectId) {
-        RDBMSQuery<CommitValidationStatus> q = new RDBMSQuery<>(wrapper, filters.get(CommitValidationStatus.class),
-                CommitHelper.getCommitParams(req, projectId));
-        // set use limit to false to collect all data in one request
-        q.setUseLimit(false);
-        return dao.get(q);
-    }
-
-    @Override
-    public void updateCommitValidationStatus(RequestWrapper wrapper, ValidationResponse r, ValidationRequest req,
-            List<CommitValidationStatus> statuses, Project p) {
-        // iterate over commit responses, and update statuses in DB
-        List<CommitValidationStatus> updatedStatuses = r
-                .getCommits()
-                .entrySet()
-                .stream()
-                .filter(e -> !ValidationResponse.NIL_HASH_PLACEHOLDER.equalsIgnoreCase(e.getKey()))
-                .map(e -> recordUpdatedValidationStatus(req, statuses, p, e))
-                .collect(Collectors.toList());
-        String fingerprint = generateRequestHash(req);
-        // update the base commit status and messages
-        dao.add(new RDBMSQuery<>(wrapper, filters.get(CommitValidationStatus.class)), updatedStatuses);
-        dao
-                .add(new RDBMSQuery<>(wrapper, filters.get(CommitValidationStatusGrouping.class)),
-                        updatedStatuses.stream().map(s -> new CommitValidationStatusGrouping(fingerprint, s)).collect(Collectors.toList()));
-    }
-
-    /**
-     * Records new or updated validation status for passed commit entry. Checks existing records and updates where
-     * appropriate, otherwise creating new entires.
-     * 
-     * @param req the complete validation request
-     * @param existingStatuses the statuses that may exist for the current request
-     * @param p the Eclipse project for the current request if it exists.
-     * @param e the current commit that is being updated
-     * @return the new or updated commit status
-     */
-    private CommitValidationStatus recordUpdatedValidationStatus(ValidationRequest req, List<CommitValidationStatus> existingStatuses,
-            Project p, Entry<String, CommitStatus> e) {
-        // get the commit for current status
-        Optional<Commit> commit = req.getCommits().stream().filter(c -> e.getKey().equals(c.getHash())).findFirst();
-        if (commit.isEmpty()) {
-            // this should always have a match (response commits are built from request commits)
-            LOGGER.error("Could not find request commit associated with commit messages for commit hash '{}'", e.getKey());
-            return null;
-        }
-        Commit c = commit.get();
-        // update the status if present, otherwise make new one.
-        Optional<CommitValidationStatus> status = existingStatuses.stream().filter(s -> e.getKey().equals(s.getCommitHash())).findFirst();
-        CommitValidationStatus base;
-        if (status.isPresent()) {
-            base = status.get();
-        } else {
-            base = new CommitValidationStatus();
-            base.setProject(CommitHelper.getProjectId(p));
-            base.setCommitHash(e.getKey());
-            base.setUserMail(c.getAuthor().getMail());
-            base.setProvider(req.getProvider());
-            base.setRepoUrl(req.getRepoUrl().toString());
-            base.setCreationDate(DateTimeHelper.now());
-            base.setEstimatedLoc(req.getEstimatedLoc());
-        }
-        base.setLastModified(DateTimeHelper.now());
-
-        // if there are errors, update validation messages
-        if (!e.getValue().getErrors().isEmpty() || (base.getErrors() != null && !base.getErrors().isEmpty())) {
-            // generate new errors, looking for errors not found in current list
-            List<CommitValidationMessage> currentErrors = base.getErrors() != null ? base.getErrors() : new ArrayList<>();
-            List<CommitValidationMessage> newErrors = e
-                    .getValue()
-                    .getErrors()
-                    .stream()
-                    .filter(err -> currentErrors.stream().noneMatch(ce -> ce.getStatusCode() == err.getCode().getValue()))
-                    .map(err -> {
-                        CommitValidationMessage m = new CommitValidationMessage();
-                        m.setAuthorEmail(c.getAuthor().getMail());
-                        m.setCommitterEmail(c.getCommitter().getMail());
-                        m.setStatusCode(err.getCode().getValue());
-                        // TODO add a checked way to set this
-                        m.setEclipseId(null);
-                        m.setProviderId(null);
-                        m.setCommit(base);
-                        return m;
-                    })
-                    .collect(Collectors.toList());
-            LOGGER.debug("Encountered {} new errors for commit with hash '{}'", newErrors.size(), e.getKey());
-            currentErrors.addAll(newErrors);
-            // remove errors that weren't encountered on this run
-            currentErrors
-                    .removeIf(err -> e.getValue().getErrors().isEmpty()
-                            || e.getValue().getErrors().stream().noneMatch(msg -> msg.getCode().getValue() == err.getStatusCode()));
-            LOGGER.trace("Encountered {} errors: {}", currentErrors.size(), currentErrors);
-            base.setErrors(currentErrors);
-        }
-        return base;
-    }
-
-    /**
-     * REQUEST VALIDATION LOGIC
-     */
-
     /**
      * Process the current request, validating that the passed commit is valid. The author and committers Eclipse Account is
      * retrieved, which are then used to check if the current commit is valid for the current project.
@@ -267,7 +130,8 @@ public class DefaultValidationService implements ValidationService {
         response.addMessage(c.getHash(), String.format("Authored by: %1$s <%2$s>", author.getName(), author.getMail()));
 
         // skip processing if a merge commit
-        if (c.getParents() != null && c.getParents().size() > 1) {
+        List<String> parents = c.getParents();
+        if (parents != null && parents.size() > 1) {
             response
                     .addMessage(c.getHash(),
                             String.format("Commit '%1$s' has multiple parents, merge commit detected, passing", c.getHash()));
@@ -419,7 +283,7 @@ public class DefaultValidationService implements ValidationService {
         }
         // check if user is a bot, either through early detection or through on-demand
         // check
-        if ((user.getIsBot() != null && user.getIsBot()) || users.userIsABot(user.getMail(), filteredProjects)) {
+        if ((user.getIsBot() != null && Boolean.TRUE.equals(user.getIsBot())) || users.userIsABot(user.getMail(), filteredProjects)) {
             LOGGER.debug("User '{} <{}>' was found to be a bot", user.getName(), user.getMail());
             return true;
         }
diff --git a/src/main/java/org/eclipsefoundation/git/eca/service/impl/DefaultValidationStatusService.java b/src/main/java/org/eclipsefoundation/git/eca/service/impl/DefaultValidationStatusService.java
new file mode 100644
index 0000000000000000000000000000000000000000..1913940b5fa99f1a00b1b62100f6dfce8aa905c8
--- /dev/null
+++ b/src/main/java/org/eclipsefoundation/git/eca/service/impl/DefaultValidationStatusService.java
@@ -0,0 +1,185 @@
+/**
+ * Copyright (c) 2023 Eclipse Foundation
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * Author: Martin Lowe <martin.lowe@eclipse-foundation.org>
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.eclipsefoundation.git.eca.service.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.apache.commons.lang3.StringUtils;
+import org.eclipsefoundation.core.helper.DateTimeHelper;
+import org.eclipsefoundation.core.model.RequestWrapper;
+import org.eclipsefoundation.core.service.CachingService;
+import org.eclipsefoundation.efservices.api.models.Project;
+import org.eclipsefoundation.git.eca.dto.CommitValidationMessage;
+import org.eclipsefoundation.git.eca.dto.CommitValidationStatus;
+import org.eclipsefoundation.git.eca.dto.CommitValidationStatusGrouping;
+import org.eclipsefoundation.git.eca.helper.CommitHelper;
+import org.eclipsefoundation.git.eca.model.Commit;
+import org.eclipsefoundation.git.eca.model.CommitStatus;
+import org.eclipsefoundation.git.eca.model.ValidationRequest;
+import org.eclipsefoundation.git.eca.model.ValidationResponse;
+import org.eclipsefoundation.git.eca.namespace.GitEcaParameterNames;
+import org.eclipsefoundation.git.eca.service.ValidationStatusService;
+import org.eclipsefoundation.persistence.dao.PersistenceDao;
+import org.eclipsefoundation.persistence.model.RDBMSQuery;
+import org.eclipsefoundation.persistence.service.FilterService;
+import org.jboss.resteasy.specimpl.MultivaluedMapImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 
+ */
+@ApplicationScoped
+public class DefaultValidationStatusService implements ValidationStatusService {
+    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultValidationStatusService.class);
+
+    @Inject
+    CachingService cache;
+    @Inject
+    PersistenceDao dao;
+    @Inject
+    FilterService filters;
+
+    @Override
+    public List<CommitValidationStatus> getHistoricValidationStatus(RequestWrapper wrapper, String fingerprint) {
+        if (StringUtils.isAllBlank(fingerprint)) {
+            return Collections.emptyList();
+        }
+        MultivaluedMap<String, String> params = new MultivaluedMapImpl<>();
+        params.add(GitEcaParameterNames.FINGERPRINT_RAW, fingerprint);
+        RDBMSQuery<CommitValidationStatusGrouping> q = new RDBMSQuery<>(wrapper, filters.get(CommitValidationStatusGrouping.class), params);
+        // set use limit to false to collect all data in one request
+        q.setUseLimit(false);
+        return dao.get(q).stream().map(statusGrouping -> statusGrouping.getCompositeId().getCommit()).collect(Collectors.toList());
+    }
+
+    @Override
+    public List<CommitValidationStatus> getHistoricValidationStatusByShas(RequestWrapper wrapper, List<String> shas) {
+        if (shas == null || shas.isEmpty()) {
+            return Collections.emptyList();
+        }
+        MultivaluedMap<String, String> params = new MultivaluedMapImpl<>();
+        params.put(GitEcaParameterNames.SHAS_RAW, shas);
+        RDBMSQuery<CommitValidationStatus> q = new RDBMSQuery<>(wrapper, filters.get(CommitValidationStatus.class), params);
+        // set use limit to false to collect all data in one request
+        q.setUseLimit(false);
+        return dao.get(q);
+    }
+
+    @Override
+    public List<CommitValidationStatus> getRequestCommitValidationStatus(RequestWrapper wrapper, ValidationRequest req, String projectId) {
+        RDBMSQuery<CommitValidationStatus> q = new RDBMSQuery<>(wrapper, filters.get(CommitValidationStatus.class),
+                CommitHelper.getCommitParams(req, projectId));
+        // set use limit to false to collect all data in one request
+        q.setUseLimit(false);
+        return dao.get(q);
+    }
+
+    @Override
+    public void updateCommitValidationStatus(RequestWrapper wrapper, ValidationResponse r, ValidationRequest req,
+            List<CommitValidationStatus> statuses, Project p) {
+        // iterate over commit responses, and update statuses in DB
+        List<CommitValidationStatus> updatedStatuses = r
+                .getCommits()
+                .entrySet()
+                .stream()
+                .filter(e -> !ValidationResponse.NIL_HASH_PLACEHOLDER.equalsIgnoreCase(e.getKey()))
+                .map(e -> recordUpdatedValidationStatus(req, statuses, p, e))
+                .collect(Collectors.toList());
+        String fingerprint = CommitHelper.generateRequestHash(req);
+        // update the base commit status and messages
+        dao.add(new RDBMSQuery<>(wrapper, filters.get(CommitValidationStatus.class)), updatedStatuses);
+        dao
+                .add(new RDBMSQuery<>(wrapper, filters.get(CommitValidationStatusGrouping.class)),
+                        updatedStatuses.stream().map(s -> new CommitValidationStatusGrouping(fingerprint, s)).collect(Collectors.toList()));
+    }
+
+    /**
+     * Records new or updated validation status for passed commit entry. Checks existing records and updates where
+     * appropriate, otherwise creating new entires.
+     * 
+     * @param req the complete validation request
+     * @param existingStatuses the statuses that may exist for the current request
+     * @param p the Eclipse project for the current request if it exists.
+     * @param e the current commit that is being updated
+     * @return the new or updated commit status
+     */
+    private CommitValidationStatus recordUpdatedValidationStatus(ValidationRequest req, List<CommitValidationStatus> existingStatuses,
+            Project p, Entry<String, CommitStatus> e) {
+        // get the commit for current status
+        Optional<Commit> commit = req.getCommits().stream().filter(c -> e.getKey().equals(c.getHash())).findFirst();
+        if (commit.isEmpty()) {
+            // this should always have a match (response commits are built from request commits)
+            LOGGER.error("Could not find request commit associated with commit messages for commit hash '{}'", e.getKey());
+            return null;
+        }
+        Commit c = commit.get();
+        // update the status if present, otherwise make new one.
+        Optional<CommitValidationStatus> status = existingStatuses.stream().filter(s -> e.getKey().equals(s.getCommitHash())).findFirst();
+        CommitValidationStatus base;
+        if (status.isPresent()) {
+            base = status.get();
+        } else {
+            base = new CommitValidationStatus();
+            base.setProject(CommitHelper.getProjectId(p));
+            base.setCommitHash(e.getKey());
+            base.setUserMail(c.getAuthor().getMail());
+            base.setProvider(req.getProvider());
+            base.setRepoUrl(req.getRepoUrl().toString());
+            base.setCreationDate(DateTimeHelper.now());
+            base.setEstimatedLoc(req.getEstimatedLoc());
+        }
+        base.setLastModified(DateTimeHelper.now());
+
+        // if there are errors, update validation messages
+        if (!e.getValue().getErrors().isEmpty() || (base.getErrors() != null && !base.getErrors().isEmpty())) {
+            // generate new errors, looking for errors not found in current list
+            List<CommitValidationMessage> currentErrors = base.getErrors() != null ? base.getErrors() : new ArrayList<>();
+            List<CommitValidationMessage> newErrors = e
+                    .getValue()
+                    .getErrors()
+                    .stream()
+                    .filter(err -> currentErrors.stream().noneMatch(ce -> ce.getStatusCode() == err.getCode().getValue()))
+                    .map(err -> {
+                        CommitValidationMessage m = new CommitValidationMessage();
+                        m.setAuthorEmail(c.getAuthor().getMail());
+                        m.setCommitterEmail(c.getCommitter().getMail());
+                        m.setStatusCode(err.getCode().getValue());
+                        // TODO add a checked way to set this
+                        m.setEclipseId(null);
+                        m.setProviderId(null);
+                        m.setCommit(base);
+                        return m;
+                    })
+                    .collect(Collectors.toList());
+            LOGGER.debug("Encountered {} new errors for commit with hash '{}'", newErrors.size(), e.getKey());
+            currentErrors.addAll(newErrors);
+            // remove errors that weren't encountered on this run
+            currentErrors
+                    .removeIf(err -> e.getValue().getErrors().isEmpty()
+                            || e.getValue().getErrors().stream().noneMatch(msg -> msg.getCode().getValue() == err.getStatusCode()));
+            LOGGER.trace("Encountered {} errors: {}", currentErrors.size(), currentErrors);
+            base.setErrors(currentErrors);
+        }
+        return base;
+    }
+
+}
diff --git a/src/test/java/org/eclipsefoundation/git/eca/helper/CommitHelperTest.java b/src/test/java/org/eclipsefoundation/git/eca/helper/CommitHelperTest.java
index 982eb6ae3e9e2a1b0f6799bb4e3b5fa0d9e74dab..9678eda50dccfa438f8baaa4f447726dd53f66ee 100644
--- a/src/test/java/org/eclipsefoundation/git/eca/helper/CommitHelperTest.java
+++ b/src/test/java/org/eclipsefoundation/git/eca/helper/CommitHelperTest.java
@@ -11,10 +11,16 @@
 **********************************************************************/
 package org.eclipsefoundation.git.eca.helper;
 
+import java.net.URI;
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.UUID;
 
 import org.eclipsefoundation.git.eca.model.Commit;
 import org.eclipsefoundation.git.eca.model.GitUser;
+import org.eclipsefoundation.git.eca.model.ValidationRequest;
+import org.eclipsefoundation.git.eca.namespace.ProviderType;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -40,17 +46,20 @@ class CommitHelperTest {
         testUser = GitUser.builder().setMail("test.user@eclipse-foundation.org").setName("Tester McTesterson").build();
 
         // basic known good commit
-        baseCommit = Commit.builder()
-                .setBody(String.format("Sample body content\n\nSigned-off-by: %s <%s>", testUser.getName(),
-                        testUser.getMail()))
-                .setHash("abc123f").setHead(false).setParents(new ArrayList<>())
-                .setSubject("Testing CommitHelper class #1337").setAuthor(testUser).setCommitter(testUser);
+        baseCommit = Commit
+                .builder()
+                .setBody(String.format("Sample body content\n\nSigned-off-by: %s <%s>", testUser.getName(), testUser.getMail()))
+                .setHash("abc123f")
+                .setHead(false)
+                .setParents(new ArrayList<>())
+                .setSubject("Testing CommitHelper class #1337")
+                .setAuthor(testUser)
+                .setCommitter(testUser);
     }
 
     @Test
     void validateCommitKnownGood() {
-        Assertions.assertTrue(CommitHelper.validateCommit(baseCommit.build()),
-                "Expected basic commit to pass validation");
+        Assertions.assertTrue(CommitHelper.validateCommit(baseCommit.build()), "Expected basic commit to pass validation");
     }
 
     @Test
@@ -61,35 +70,156 @@ class CommitHelperTest {
     @Test
     void validateCommitNoAuthorMail() {
         baseCommit.setAuthor(GitUser.builder().setName("Some Name").build());
-        Assertions.assertFalse(CommitHelper.validateCommit(baseCommit.build()),
-                "Expected basic commit to fail validation w/ no author mail address");
+        Assertions
+                .assertFalse(CommitHelper.validateCommit(baseCommit.build()),
+                        "Expected basic commit to fail validation w/ no author mail address");
     }
 
     @Test
     void validateCommitNoCommitterMail() {
         baseCommit.setCommitter(GitUser.builder().setName("Some Name").build());
-        Assertions.assertFalse(CommitHelper.validateCommit(baseCommit.build()),
-                "Expected basic commit to fail validation w/ no committer mail address");
+        Assertions
+                .assertFalse(CommitHelper.validateCommit(baseCommit.build()),
+                        "Expected basic commit to fail validation w/ no committer mail address");
     }
 
     @Test
     void validateCommitNoBody() {
         baseCommit.setBody(null);
-        Assertions.assertTrue(CommitHelper.validateCommit(baseCommit.build()),
-                "Expected basic commit to pass validation w/ no body");
+        Assertions.assertTrue(CommitHelper.validateCommit(baseCommit.build()), "Expected basic commit to pass validation w/ no body");
     }
 
     @Test
     void validateCommitNoParents() {
         baseCommit.setParents(new ArrayList<>());
-        Assertions.assertTrue(CommitHelper.validateCommit(baseCommit.build()),
-                "Expected basic commit to pass validation w/ no parents");
+        Assertions.assertTrue(CommitHelper.validateCommit(baseCommit.build()), "Expected basic commit to pass validation w/ no parents");
     }
 
     @Test
     void validateCommitNoSubject() {
         baseCommit.setSubject(null);
-        Assertions.assertTrue(CommitHelper.validateCommit(baseCommit.build()),
-                "Expected basic commit to pass validation w/ no subject");
+        Assertions.assertTrue(CommitHelper.validateCommit(baseCommit.build()), "Expected basic commit to pass validation w/ no subject");
+    }
+
+    @Test
+    void generateRequestHash_reproducible() {
+        ValidationRequest vr = generateBaseRequest();
+        String fingerprint = CommitHelper.generateRequestHash(vr);
+        // if pushing the same set of commits without change the fingerprint won't change
+        Assertions.assertEquals(fingerprint, CommitHelper.generateRequestHash(vr));
+    }
+
+    @Test
+    void generateRequestHash_changesWithRepoURL() {
+        GitUser g1 = GitUser.builder().setName("The Wizard").setMail("code.wiz@important.co").build();
+
+        List<Commit> commits = new ArrayList<>();
+        // create sample commits
+        Commit c1 = Commit
+                .builder()
+                .setAuthor(g1)
+                .setCommitter(g1)
+                .setBody("Signed-off-by: The Wizard <code.wiz@important.co>")
+                .setHash(UUID.randomUUID().toString())
+                .setSubject("All of the things")
+                .setParents(Collections.emptyList())
+                .build();
+        commits.add(c1);
+
+        // generate initial fingerprint
+        ValidationRequest vr = ValidationRequest
+                .builder()
+                .setStrictMode(false)
+                .setProvider(ProviderType.GITHUB)
+                .setRepoUrl(URI.create("http://www.github.com/eclipsefdn/sample"))
+                .setCommits(commits)
+                .build();
+        String fingerprint = CommitHelper.generateRequestHash(vr);
+        // generate request with different repo url
+        vr = ValidationRequest
+                .builder()
+                .setStrictMode(false)
+                .setProvider(ProviderType.GITHUB)
+                .setRepoUrl(URI.create("http://www.github.com/eclipsefdn/other-sample"))
+                .setCommits(commits)
+                .build();
+        // fingerprint should change based on repo URL to reduce risk of collision
+        Assertions.assertNotEquals(fingerprint, CommitHelper.generateRequestHash(vr));
+    }
+
+    @Test
+    void generateRequestHash_changesWithNewCommits() {
+        GitUser g1 = GitUser.builder().setName("The Wizard").setMail("code.wiz@important.co").build();
+        List<Commit> commits = new ArrayList<>();
+        // create sample commits
+        Commit c1 = Commit
+                .builder()
+                .setAuthor(g1)
+                .setCommitter(g1)
+                .setBody("Signed-off-by: The Wizard <code.wiz@important.co>")
+                .setHash(UUID.randomUUID().toString())
+                .setSubject("All of the things")
+                .setParents(Collections.emptyList())
+                .build();
+        commits.add(c1);
+
+        // generate initial fingerprint
+        ValidationRequest vr = ValidationRequest
+                .builder()
+                .setStrictMode(false)
+                .setProvider(ProviderType.GITHUB)
+                .setRepoUrl(URI.create("http://www.github.com/eclipsefdn/sample"))
+                .setCommits(commits)
+                .build();
+        String fingerprint = CommitHelper.generateRequestHash(vr);
+        Commit c2 = Commit
+                .builder()
+                .setAuthor(g1)
+                .setCommitter(g1)
+                .setBody("Signed-off-by: The Wizard <code.wiz@important.co>")
+                .setHash(UUID.randomUUID().toString())
+                .setSubject("All of the things")
+                .setParents(Collections.emptyList())
+                .build();
+        commits.add(c2);
+        // generate request with different repo url
+        vr = ValidationRequest
+                .builder()
+                .setStrictMode(false)
+                .setProvider(ProviderType.GITHUB)
+                .setRepoUrl(URI.create("http://www.github.com/eclipsefdn/other-sample"))
+                .setCommits(commits)
+                .build();
+        // each commit added should modify the fingerprint at least slightly
+        Assertions.assertNotEquals(fingerprint, CommitHelper.generateRequestHash(vr));
+    }
+
+    /**
+     * Used when a random validationRequest is needed and will not need to be recreated/modified. Base request should
+     * register as a commit for the test `sample.proj` project.
+     * 
+     * @return random basic validation request.
+     */
+    private ValidationRequest generateBaseRequest() {
+        GitUser g1 = GitUser.builder().setName("The Wizard").setMail("code.wiz@important.co").build();
+        List<Commit> commits = new ArrayList<>();
+        // create sample commits
+        Commit c1 = Commit
+                .builder()
+                .setAuthor(g1)
+                .setCommitter(g1)
+                .setBody("Signed-off-by: The Wizard <code.wiz@important.co>")
+                .setHash(UUID.randomUUID().toString())
+                .setSubject("All of the things")
+                .setParents(Collections.emptyList())
+                .build();
+        commits.add(c1);
+        return ValidationRequest
+                .builder()
+                .setStrictMode(false)
+                .setProvider(ProviderType.GITHUB)
+                .setRepoUrl(URI.create("http://www.github.com/eclipsefdn/sample"))
+                .setCommits(commits)
+                .build();
     }
 }
diff --git a/src/test/java/org/eclipsefoundation/git/eca/service/impl/DefaultValidationServiceTest.java b/src/test/java/org/eclipsefoundation/git/eca/service/impl/DefaultValidationServiceTest.java
deleted file mode 100644
index 8b9d9d82e1a2033ef361e6090d6ea77e49266ea8..0000000000000000000000000000000000000000
--- a/src/test/java/org/eclipsefoundation/git/eca/service/impl/DefaultValidationServiceTest.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*********************************************************************
-* Copyright (c) 2022 Eclipse Foundation.
-*
-* This program and the accompanying materials are made
-* available under the terms of the Eclipse Public License 2.0
-* which is available at https://www.eclipse.org/legal/epl-2.0/
-*
-* Author: Martin Lowe <martin.lowe@eclipse-foundation.org>
-*
-* SPDX-License-Identifier: EPL-2.0
-**********************************************************************/
-package org.eclipsefoundation.git.eca.service.impl;
-
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.UUID;
-
-import javax.inject.Inject;
-
-import org.eclipsefoundation.core.model.FlatRequestWrapper;
-import org.eclipsefoundation.core.model.RequestWrapper;
-import org.eclipsefoundation.git.eca.dto.CommitValidationStatus;
-import org.eclipsefoundation.git.eca.model.Commit;
-import org.eclipsefoundation.git.eca.model.GitUser;
-import org.eclipsefoundation.git.eca.model.ValidationRequest;
-import org.eclipsefoundation.git.eca.namespace.ProviderType;
-import org.eclipsefoundation.git.eca.service.ValidationService;
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.Test;
-
-import io.quarkus.test.junit.QuarkusTest;
-
-@QuarkusTest
-class DefaultValidationServiceTest {
-
-    @Inject
-    ValidationService validation;
-
-    @Test
-    void generateRequestHash_reproducible() {
-        ValidationRequest vr = generateBaseRequest();
-        String fingerprint = validation.generateRequestHash(vr);
-        // if pushing the same set of commits without change the fingerprint won't change
-        Assertions.assertEquals(fingerprint, validation.generateRequestHash(vr));
-    }
-
-    @Test
-    void generateRequestHash_changesWithRepoURL() {
-        GitUser g1 = GitUser.builder().setName("The Wizard").setMail("code.wiz@important.co").build();
-
-        List<Commit> commits = new ArrayList<>();
-        // create sample commits
-        Commit c1 = Commit.builder().setAuthor(g1).setCommitter(g1)
-                .setBody("Signed-off-by: The Wizard <code.wiz@important.co>")
-                .setHash(UUID.randomUUID().toString())
-                .setSubject("All of the things").setParents(Collections.emptyList()).build();
-        commits.add(c1);
-
-        // generate initial fingerprint
-        ValidationRequest vr = ValidationRequest.builder().setStrictMode(false).setProvider(ProviderType.GITHUB)
-                .setRepoUrl(URI.create("http://www.github.com/eclipsefdn/sample")).setCommits(commits)
-                .build();
-        String fingerprint = validation.generateRequestHash(vr);
-        // generate request with different repo url
-        vr = ValidationRequest.builder().setStrictMode(false).setProvider(ProviderType.GITHUB)
-                .setRepoUrl(URI.create("http://www.github.com/eclipsefdn/other-sample"))
-                .setCommits(commits).build();
-        // fingerprint should change based on repo URL to reduce risk of collision
-        Assertions.assertNotEquals(fingerprint, validation.generateRequestHash(vr));
-    }
-
-    @Test
-    void generateRequestHash_changesWithNewCommits() {
-        GitUser g1 = GitUser.builder().setName("The Wizard").setMail("code.wiz@important.co").build();
-        List<Commit> commits = new ArrayList<>();
-        // create sample commits
-        Commit c1 = Commit.builder().setAuthor(g1).setCommitter(g1)
-                .setBody("Signed-off-by: The Wizard <code.wiz@important.co>")
-                .setHash(UUID.randomUUID().toString())
-                .setSubject("All of the things").setParents(Collections.emptyList()).build();
-        commits.add(c1);
-
-        // generate initial fingerprint
-        ValidationRequest vr = ValidationRequest.builder().setStrictMode(false).setProvider(ProviderType.GITHUB)
-                .setRepoUrl(URI.create("http://www.github.com/eclipsefdn/sample")).setCommits(commits)
-                .build();
-        String fingerprint = validation.generateRequestHash(vr);
-        Commit c2 = Commit.builder().setAuthor(g1).setCommitter(g1)
-                .setBody("Signed-off-by: The Wizard <code.wiz@important.co>")
-                .setHash(UUID.randomUUID().toString())
-                .setSubject("All of the things").setParents(Collections.emptyList()).build();
-        commits.add(c2);
-        // generate request with different repo url
-        vr = ValidationRequest.builder().setStrictMode(false).setProvider(ProviderType.GITHUB)
-                .setRepoUrl(URI.create("http://www.github.com/eclipsefdn/other-sample"))
-                .setCommits(commits).build();
-        // each commit added should modify the fingerprint at least slightly
-        Assertions.assertNotEquals(fingerprint, validation.generateRequestHash(vr));
-    }
-
-    @Test
-    void getHistoricValidationStatus_noFingerprint() {
-        RequestWrapper wrap = new FlatRequestWrapper(URI.create("http://localhost/git/eca"));
-        Assertions.assertTrue(validation.getHistoricValidationStatus(wrap, null).isEmpty());
-        Assertions.assertTrue(validation.getHistoricValidationStatus(wrap, " ").isEmpty());
-        Assertions.assertTrue(validation.getHistoricValidationStatus(wrap, "").isEmpty());
-    }
-
-    @Test
-    void getHistoricValidationStatus_noResultsForFingerprint() {
-        RequestWrapper wrap = new FlatRequestWrapper(URI.create("http://localhost/git/eca"));
-        Assertions.assertTrue(
-                validation.getHistoricValidationStatus(wrap, UUID.randomUUID().toString()).isEmpty());
-    }
-
-    @Test
-    void getHistoricValidationStatus_success() {
-        RequestWrapper wrap = new FlatRequestWrapper(URI.create("http://localhost/git/eca"));
-        Assertions.assertTrue(!validation.getHistoricValidationStatus(wrap, "957706b0f31e0ccfc5287c0ebc62dc79")
-                .isEmpty());
-    }
-
-    @Test
-    void getRequestCommitValidationStatus_noneExisting() {
-        RequestWrapper wrap = new FlatRequestWrapper(URI.create("http://localhost/git/eca"));
-        ValidationRequest vr = generateBaseRequest();
-        List<CommitValidationStatus> out = validation.getRequestCommitValidationStatus(wrap, vr, "sample.proj");
-        // should always return non-null, should be empty w/ no results as there
-        // shouldn't be a matching status
-        Assertions.assertTrue(out.isEmpty());
-    }
-
-    @Test
-    void getRequestCommitValidationStatus_existing() {
-        // create request that lines up with one of the existing test commit validation statuses
-        RequestWrapper wrap = new FlatRequestWrapper(URI.create("http://localhost/git/eca"));
-        GitUser g1 = GitUser.builder().setName("The Wizard").setMail("code.wiz@important.co").build();
-        List<Commit> commits = new ArrayList<>();
-        // create sample commits
-        Commit c1 = Commit.builder().setAuthor(g1).setCommitter(g1)
-                .setBody("Signed-off-by: The Wizard <code.wiz@important.co>").setHash("123456789")
-                .setSubject("All of the things").setParents(Collections.emptyList()).build();
-        commits.add(c1);
-        ValidationRequest vr = ValidationRequest.builder().setStrictMode(false).setProvider(ProviderType.GITHUB)
-                .setRepoUrl(URI.create("http://www.github.com/eclipsefdn/sample")).setCommits(commits)
-                .build();
-        List<CommitValidationStatus> out = validation.getRequestCommitValidationStatus(wrap, vr, "sample.proj");
-        // should contain one of the test status objects
-        Assertions.assertTrue(!out.isEmpty());
-    }
-
-    @Test
-    void getRequestCommitValidationStatus_noProjectWithResults() {
-        // create request that lines up with one of the existing test commit validation statuses
-        RequestWrapper wrap = new FlatRequestWrapper(URI.create("http://localhost/git/eca"));
-        GitUser g1 = GitUser.builder().setName("The Wizard").setMail("code.wiz@important.co").build();
-        List<Commit> commits = new ArrayList<>();
-        // create sample commits
-        Commit c1 = Commit.builder().setAuthor(g1).setCommitter(g1)
-                .setBody("Signed-off-by: The Wizard <code.wiz@important.co>").setHash("abc123def456")
-                .setSubject("All of the things").setParents(Collections.emptyList()).build();
-        commits.add(c1);
-        ValidationRequest vr = ValidationRequest.builder().setStrictMode(false).setProvider(ProviderType.GITHUB)
-                .setRepoUrl(URI.create("http://www.github.com/eclipsefdn/sample")).setCommits(commits)
-                .build();
-        List<CommitValidationStatus> out = validation.getRequestCommitValidationStatus(wrap, vr, null);
-        // should contain one of the test status objects
-        Assertions.assertTrue(!out.isEmpty());
-    }
-
-    @Test
-    void getRequestCommitValidationStatus_noProjectWithNoResults() {
-        RequestWrapper wrap = new FlatRequestWrapper(URI.create("http://localhost/git/eca"));
-        ValidationRequest vr = generateBaseRequest();
-        List<CommitValidationStatus> out = validation.getRequestCommitValidationStatus(wrap, vr, null);
-        // should contain one of the test status objects
-        Assertions.assertTrue(out.isEmpty());
-    }
-
-    /**
-     * Used when a random validationRequest is needed and will not need to be
-     * recreated/modified. Base request should register as a commit for the test
-     * `sample.proj` project.
-     * 
-     * @return random basic validation request.
-     */
-    private ValidationRequest generateBaseRequest() {
-        GitUser g1 = GitUser.builder().setName("The Wizard").setMail("code.wiz@important.co").build();
-        List<Commit> commits = new ArrayList<>();
-        // create sample commits
-        Commit c1 = Commit.builder().setAuthor(g1).setCommitter(g1)
-                .setBody("Signed-off-by: The Wizard <code.wiz@important.co>")
-                .setHash(UUID.randomUUID().toString())
-                .setSubject("All of the things").setParents(Collections.emptyList()).build();
-        commits.add(c1);
-        return ValidationRequest.builder().setStrictMode(false).setProvider(ProviderType.GITHUB)
-                .setRepoUrl(URI.create("http://www.github.com/eclipsefdn/sample")).setCommits(commits)
-                .build();
-    }
-}
diff --git a/src/test/java/org/eclipsefoundation/git/eca/service/impl/DefaultValidationStatusServiceTest.java b/src/test/java/org/eclipsefoundation/git/eca/service/impl/DefaultValidationStatusServiceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..10d250776c1f9e3c1e4302929d2d608c1cc336c3
--- /dev/null
+++ b/src/test/java/org/eclipsefoundation/git/eca/service/impl/DefaultValidationStatusServiceTest.java
@@ -0,0 +1,166 @@
+/*********************************************************************
+* Copyright (c) 2022 Eclipse Foundation.
+*
+* This program and the accompanying materials are made
+* available under the terms of the Eclipse Public License 2.0
+* which is available at https://www.eclipse.org/legal/epl-2.0/
+*
+* Author: Martin Lowe <martin.lowe@eclipse-foundation.org>
+*
+* SPDX-License-Identifier: EPL-2.0
+**********************************************************************/
+package org.eclipsefoundation.git.eca.service.impl;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.UUID;
+
+import javax.inject.Inject;
+
+import org.eclipsefoundation.core.model.FlatRequestWrapper;
+import org.eclipsefoundation.core.model.RequestWrapper;
+import org.eclipsefoundation.git.eca.dto.CommitValidationStatus;
+import org.eclipsefoundation.git.eca.model.Commit;
+import org.eclipsefoundation.git.eca.model.GitUser;
+import org.eclipsefoundation.git.eca.model.ValidationRequest;
+import org.eclipsefoundation.git.eca.namespace.ProviderType;
+import org.eclipsefoundation.git.eca.service.ValidationStatusService;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import io.quarkus.test.junit.QuarkusTest;
+
+@QuarkusTest
+class DefaultValidationStatusServiceTest {
+
+    @Inject
+    ValidationStatusService validationStatus;
+
+    @Test
+    void getHistoricValidationStatus_noFingerprint() {
+        RequestWrapper wrap = new FlatRequestWrapper(URI.create("http://localhost/git/eca"));
+        Assertions.assertTrue(validationStatus.getHistoricValidationStatus(wrap, null).isEmpty());
+        Assertions.assertTrue(validationStatus.getHistoricValidationStatus(wrap, " ").isEmpty());
+        Assertions.assertTrue(validationStatus.getHistoricValidationStatus(wrap, "").isEmpty());
+    }
+
+    @Test
+    void getHistoricValidationStatus_noResultsForFingerprint() {
+        RequestWrapper wrap = new FlatRequestWrapper(URI.create("http://localhost/git/eca"));
+        Assertions.assertTrue(validationStatus.getHistoricValidationStatus(wrap, UUID.randomUUID().toString()).isEmpty());
+    }
+
+    @Test
+    void getHistoricValidationStatus_success() {
+        RequestWrapper wrap = new FlatRequestWrapper(URI.create("http://localhost/git/eca"));
+        Assertions.assertTrue(!validationStatus.getHistoricValidationStatus(wrap, "957706b0f31e0ccfc5287c0ebc62dc79").isEmpty());
+    }
+
+    @Test
+    void getRequestCommitValidationStatus_noneExisting() {
+        RequestWrapper wrap = new FlatRequestWrapper(URI.create("http://localhost/git/eca"));
+        ValidationRequest vr = generateBaseRequest();
+        List<CommitValidationStatus> out = validationStatus.getRequestCommitValidationStatus(wrap, vr, "sample.proj");
+        // should always return non-null, should be empty w/ no results as there
+        // shouldn't be a matching status
+        Assertions.assertTrue(out.isEmpty());
+    }
+
+    @Test
+    void getRequestCommitValidationStatus_existing() {
+        // create request that lines up with one of the existing test commit validation statuses
+        RequestWrapper wrap = new FlatRequestWrapper(URI.create("http://localhost/git/eca"));
+        GitUser g1 = GitUser.builder().setName("The Wizard").setMail("code.wiz@important.co").build();
+        List<Commit> commits = new ArrayList<>();
+        // create sample commits
+        Commit c1 = Commit
+                .builder()
+                .setAuthor(g1)
+                .setCommitter(g1)
+                .setBody("Signed-off-by: The Wizard <code.wiz@important.co>")
+                .setHash("123456789")
+                .setSubject("All of the things")
+                .setParents(Collections.emptyList())
+                .build();
+        commits.add(c1);
+        ValidationRequest vr = ValidationRequest
+                .builder()
+                .setStrictMode(false)
+                .setProvider(ProviderType.GITHUB)
+                .setRepoUrl(URI.create("http://www.github.com/eclipsefdn/sample"))
+                .setCommits(commits)
+                .build();
+        List<CommitValidationStatus> out = validationStatus.getRequestCommitValidationStatus(wrap, vr, "sample.proj");
+        // should contain one of the test status objects
+        Assertions.assertTrue(!out.isEmpty());
+    }
+
+    @Test
+    void getRequestCommitValidationStatus_noProjectWithResults() {
+        // create request that lines up with one of the existing test commit validation statuses
+        RequestWrapper wrap = new FlatRequestWrapper(URI.create("http://localhost/git/eca"));
+        GitUser g1 = GitUser.builder().setName("The Wizard").setMail("code.wiz@important.co").build();
+        List<Commit> commits = new ArrayList<>();
+        // create sample commits
+        Commit c1 = Commit
+                .builder()
+                .setAuthor(g1)
+                .setCommitter(g1)
+                .setBody("Signed-off-by: The Wizard <code.wiz@important.co>")
+                .setHash("abc123def456")
+                .setSubject("All of the things")
+                .setParents(Collections.emptyList())
+                .build();
+        commits.add(c1);
+        ValidationRequest vr = ValidationRequest
+                .builder()
+                .setStrictMode(false)
+                .setProvider(ProviderType.GITHUB)
+                .setRepoUrl(URI.create("http://www.github.com/eclipsefdn/sample"))
+                .setCommits(commits)
+                .build();
+        List<CommitValidationStatus> out = validationStatus.getRequestCommitValidationStatus(wrap, vr, null);
+        // should contain one of the test status objects
+        Assertions.assertTrue(!out.isEmpty());
+    }
+
+    @Test
+    void getRequestCommitValidationStatus_noProjectWithNoResults() {
+        RequestWrapper wrap = new FlatRequestWrapper(URI.create("http://localhost/git/eca"));
+        ValidationRequest vr = generateBaseRequest();
+        List<CommitValidationStatus> out = validationStatus.getRequestCommitValidationStatus(wrap, vr, null);
+        // should contain one of the test status objects
+        Assertions.assertTrue(out.isEmpty());
+    }
+
+    /**
+     * Used when a random validationRequest is needed and will not need to be recreated/modified. Base request should
+     * register as a commit for the test `sample.proj` project.
+     * 
+     * @return random basic validation request.
+     */
+    private ValidationRequest generateBaseRequest() {
+        GitUser g1 = GitUser.builder().setName("The Wizard").setMail("code.wiz@important.co").build();
+        List<Commit> commits = new ArrayList<>();
+        // create sample commits
+        Commit c1 = Commit
+                .builder()
+                .setAuthor(g1)
+                .setCommitter(g1)
+                .setBody("Signed-off-by: The Wizard <code.wiz@important.co>")
+                .setHash(UUID.randomUUID().toString())
+                .setSubject("All of the things")
+                .setParents(Collections.emptyList())
+                .build();
+        commits.add(c1);
+        return ValidationRequest
+                .builder()
+                .setStrictMode(false)
+                .setProvider(ProviderType.GITHUB)
+                .setRepoUrl(URI.create("http://www.github.com/eclipsefdn/sample"))
+                .setCommits(commits)
+                .build();
+    }
+}