diff --git a/config/mariadb/initdb.d/init.sql b/config/mariadb/initdb.d/init.sql
index 2a6abea6219dc978d7561e8eb845a69a6505154a..45938283d5c8f57751c83219404ca36206f9670e 100644
--- a/config/mariadb/initdb.d/init.sql
+++ b/config/mariadb/initdb.d/init.sql
@@ -12,11 +12,13 @@ CREATE TABLE IF NOT EXISTS `CommitValidationMessage` (
 CREATE TABLE IF NOT EXISTS `CommitValidationStatus` (
   `id` SERIAL,
   `commitHash` varchar(100) NOT NULL,
+  `userMail` varchar(100) NOT NULL,
   `project` varchar(100) NOT NULL,
   `lastModified` datetime DEFAULT NULL,
   `creationDate` datetime DEFAULT NULL,
   `provider` varchar(100) NOT NULL,
   `repoUrl` varchar(255) DEFAULT NULL,
+  `entimatedLoc` int(11) DEFAULT NULL,
   PRIMARY KEY (`id`)
 );
 
diff --git a/src/main/java/org/eclipsefoundation/git/eca/config/EclipseQuteTemplateExtensions.java b/src/main/java/org/eclipsefoundation/git/eca/config/EclipseQuteTemplateExtensions.java
index adef078e3b23ad57069dc625cfece3b864770f21..b5b7bdacc995c52269baee97cf92221970dd0fcc 100644
--- a/src/main/java/org/eclipsefoundation/git/eca/config/EclipseQuteTemplateExtensions.java
+++ b/src/main/java/org/eclipsefoundation/git/eca/config/EclipseQuteTemplateExtensions.java
@@ -124,4 +124,8 @@ public class EclipseQuteTemplateExtensions {
         }
         return out;
     }
+
+    private EclipseQuteTemplateExtensions() {
+        
+    }
 }
diff --git a/src/main/java/org/eclipsefoundation/git/eca/dto/CommitValidationMessage.java b/src/main/java/org/eclipsefoundation/git/eca/dto/CommitValidationMessage.java
index 1b4a7cfc7ddaaa281e487e8b1eba04ea3d3ae5f5..2bb409ed17a947de9e719bd9fc05eb6a9aca9686 100644
--- a/src/main/java/org/eclipsefoundation/git/eca/dto/CommitValidationMessage.java
+++ b/src/main/java/org/eclipsefoundation/git/eca/dto/CommitValidationMessage.java
@@ -11,6 +11,7 @@
 **********************************************************************/
 package org.eclipsefoundation.git.eca.dto;
 
+import java.io.Serializable;
 import java.util.List;
 import java.util.Objects;
 import java.util.stream.Collectors;
@@ -38,7 +39,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
 
 @Table
 @Entity
-public class CommitValidationMessage extends BareNode {
+public class CommitValidationMessage extends BareNode implements Serializable{
     public static final DtoTable TABLE = new DtoTable(CommitValidationMessage.class, "cvm");
 
     @Id
diff --git a/src/main/java/org/eclipsefoundation/git/eca/helper/JwtHelper.java b/src/main/java/org/eclipsefoundation/git/eca/helper/JwtHelper.java
index 3fd168db02f562e8972c389950d032ce419ea720..a903c7090e166c01f3d66a0aa5c3d73c596f5205 100644
--- a/src/main/java/org/eclipsefoundation/git/eca/helper/JwtHelper.java
+++ b/src/main/java/org/eclipsefoundation/git/eca/helper/JwtHelper.java
@@ -45,10 +45,10 @@ public class JwtHelper {
     @ConfigProperty(name = "smallrye.jwt.sign.key.location")
     String location;
     @ConfigProperty(name = "eclipse.github.default-api-version", defaultValue = "2022-11-28")
-    String apiVersion;
+    protected String apiVersion;
 
     @RestClient
-    GithubAPI ghApi;
+    protected GithubAPI ghApi;
 
     @Inject
     JWTParser parser;
diff --git a/src/main/java/org/eclipsefoundation/git/eca/model/CommitStatus.java b/src/main/java/org/eclipsefoundation/git/eca/model/CommitStatus.java
index 47361178b52b529a5f2c63c2f20f264ab246846d..bb740946330fc3d75575823760e52251213d8027 100644
--- a/src/main/java/org/eclipsefoundation/git/eca/model/CommitStatus.java
+++ b/src/main/java/org/eclipsefoundation/git/eca/model/CommitStatus.java
@@ -14,6 +14,8 @@ package org.eclipsefoundation.git.eca.model;
 import java.util.ArrayList;
 import java.util.List;
 
+import javax.annotation.Nullable;
+
 import org.eclipsefoundation.git.eca.namespace.APIStatusCode;
 
 import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
@@ -76,6 +78,7 @@ public abstract class CommitStatus {
     public abstract static class CommitStatusMessage {
         public abstract APIStatusCode getCode();
 
+        @Nullable
         public abstract String getMessage();
 
         public static Builder builder() {
@@ -87,7 +90,7 @@ public abstract class CommitStatus {
         public abstract static class Builder {
             public abstract Builder setCode(APIStatusCode code);
 
-            public abstract Builder setMessage(String message);
+            public abstract Builder setMessage(@Nullable String message);
 
             public abstract CommitStatusMessage build();
         }
diff --git a/src/main/java/org/eclipsefoundation/git/eca/model/ValidationRequest.java b/src/main/java/org/eclipsefoundation/git/eca/model/ValidationRequest.java
index e1e44475a6fb8e9697d28a1e57e78d4701e50fe6..5d1d70710e96eaa92e00e9c6d0f96fc5a83ee380 100644
--- a/src/main/java/org/eclipsefoundation/git/eca/model/ValidationRequest.java
+++ b/src/main/java/org/eclipsefoundation/git/eca/model/ValidationRequest.java
@@ -40,6 +40,7 @@ public abstract class ValidationRequest {
 
     public abstract List<Commit> getCommits();
 
+    @Nullable
     public abstract ProviderType getProvider();
 
     @Nullable
@@ -49,6 +50,8 @@ public abstract class ValidationRequest {
     @JsonProperty("strictMode")
     public abstract Boolean getStrictMode();
 
+    public abstract Builder toBuilder();
+
     public static Builder builder() {
         return new AutoValue_ValidationRequest.Builder().setStrictMode(false).setCommits(new ArrayList<>());
     }
@@ -61,7 +64,7 @@ public abstract class ValidationRequest {
 
         public abstract Builder setCommits(List<Commit> commits);
 
-        public abstract Builder setProvider(ProviderType provider);
+        public abstract Builder setProvider(@Nullable ProviderType provider);
 
         public abstract Builder setEstimatedLoc(@Nullable Integer estimatedLoc);
 
diff --git a/src/main/java/org/eclipsefoundation/git/eca/model/ValidationResponse.java b/src/main/java/org/eclipsefoundation/git/eca/model/ValidationResponse.java
index 0ba5ad5cf8e192fef657984827c63dcceda80636..60a38dc484db54368b2c90a9a7a32625b4e5b936 100644
--- a/src/main/java/org/eclipsefoundation/git/eca/model/ValidationResponse.java
+++ b/src/main/java/org/eclipsefoundation/git/eca/model/ValidationResponse.java
@@ -15,6 +15,7 @@ import java.time.ZonedDateTime;
 import java.util.HashMap;
 import java.util.Map;
 
+import javax.annotation.Nullable;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
 
@@ -46,6 +47,7 @@ public abstract class ValidationResponse {
 
     public abstract boolean getStrictMode();
 
+    @Nullable
     public abstract String getFingerprint();
 
     public boolean getPassed() {
@@ -130,7 +132,7 @@ public abstract class ValidationResponse {
 
         public abstract Builder setStrictMode(boolean strictMode);
 
-        public abstract Builder setFingerprint(String fingerprint);
+        public abstract Builder setFingerprint(@Nullable String fingerprint);
 
         public abstract ValidationResponse build();
     }
diff --git a/src/main/java/org/eclipsefoundation/git/eca/namespace/WebhookHeaders.java b/src/main/java/org/eclipsefoundation/git/eca/namespace/WebhookHeaders.java
new file mode 100644
index 0000000000000000000000000000000000000000..017f47c47ea7502b4cfe94a31499bc46e9bf1257
--- /dev/null
+++ b/src/main/java/org/eclipsefoundation/git/eca/namespace/WebhookHeaders.java
@@ -0,0 +1,27 @@
+/*********************************************************************
+* 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: Zachary Sabourin <zachary.sabourin@eclipse-foundation.org>
+*
+* SPDX-License-Identifier: EPL-2.0
+**********************************************************************/
+package org.eclipsefoundation.git.eca.namespace;
+
+/** 
+ * A Helper class used to centralize the incoming webhook header values
+*/
+public final class WebhookHeaders {
+    
+    public static final String GITLAB_EVENT = "X-Gitlab-Event";
+
+    public static final String GITHUB_EVENT = "X-GitHub-Event";
+    public static final String GITHUB_DELIVERY = "X-GitHub-Delivery";
+
+    private WebhookHeaders() {
+
+    }
+}
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 a4569876f97c4d9078eb8f8c56c626d248117d66..f02a4015b2c7a0ca52dccc5431185caefd30ab62 100644
--- a/src/main/java/org/eclipsefoundation/git/eca/resource/GithubWebhooksResource.java
+++ b/src/main/java/org/eclipsefoundation/git/eca/resource/GithubWebhooksResource.java
@@ -33,6 +33,7 @@ import org.eclipsefoundation.git.eca.model.RevalidationResponse;
 import org.eclipsefoundation.git.eca.model.ValidationRequest;
 import org.eclipsefoundation.git.eca.namespace.GitEcaParameterNames;
 import org.eclipsefoundation.git.eca.namespace.HCaptchaErrorCodes;
+import org.eclipsefoundation.git.eca.namespace.WebhookHeaders;
 import org.jboss.resteasy.annotations.jaxrs.HeaderParam;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -63,8 +64,8 @@ public class GithubWebhooksResource extends GithubAdjacentResource {
      * @return an OK status when done processing.
      */
     @POST
-    public Response processGithubWebhook(@HeaderParam("X-GitHub-Delivery") String deliveryId,
-            @HeaderParam("X-GitHub-Hook-ID") String hookId, @HeaderParam("X-GitHub-Event") String eventType, GithubWebhookRequest request) {
+    public Response processGithubWebhook(@HeaderParam(WebhookHeaders.GITHUB_DELIVERY) String deliveryId,
+            @HeaderParam(WebhookHeaders.GITHUB_EVENT) String eventType, GithubWebhookRequest request) {
         // If event isn't a pr event, drop as we don't process them
         if (!"pull_request".equalsIgnoreCase(eventType)) {
             return Response.ok().build();
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 8c612938e0e53d23b617d0dce85f31af71ba696f..8fd1b44f975684f587066fbad69bf7b836aaafbd 100644
--- a/src/main/java/org/eclipsefoundation/git/eca/resource/StatusResource.java
+++ b/src/main/java/org/eclipsefoundation/git/eca/resource/StatusResource.java
@@ -83,7 +83,7 @@ public class StatusResource extends GithubAdjacentResource {
     public Response getCommitValidationUI(@PathParam("fingerprint") String fingerprint) {
         List<CommitValidationStatus> statuses = validation.getHistoricValidationStatus(wrapper, fingerprint);
         if (statuses.isEmpty()) {
-            return Response.status(404).build();
+            throw new NotFoundException(String.format("Fingerprint '%s' not found", fingerprint));
         }
         List<Project> ps = projects.retrieveProjectsForRepoURL(statuses.get(0).getRepoUrl(), statuses.get(0).getProvider());
         return Response
diff --git a/src/main/java/org/eclipsefoundation/git/eca/resource/ValidationResource.java b/src/main/java/org/eclipsefoundation/git/eca/resource/ValidationResource.java
index 36eb596b693a4ffc0dd85e751f02c2a8116d7ea9..9d4f0c5ff6a4cd9cbeaaac52e237ed0e41dc2799 100644
--- a/src/main/java/org/eclipsefoundation/git/eca/resource/ValidationResource.java
+++ b/src/main/java/org/eclipsefoundation/git/eca/resource/ValidationResource.java
@@ -25,6 +25,7 @@ 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.core.model.RequestWrapper;
 import org.eclipsefoundation.core.service.CachingService;
 import org.eclipsefoundation.git.eca.api.models.EclipseUser;
@@ -117,7 +118,7 @@ public class ValidationResource {
             messages.add("A commit is required to validate");
         }
         // check that we have a repo set
-        if (req.getRepoUrl() == null) {
+        if (req.getRepoUrl() == null || StringUtils.isBlank(req.getRepoUrl().getPath())) {
             messages.add("A base repo URL needs to be set in order to validate");
         }
         // check that we have a type set
diff --git a/src/main/java/org/eclipsefoundation/git/eca/resource/WebhooksResource.java b/src/main/java/org/eclipsefoundation/git/eca/resource/WebhooksResource.java
index a9fd5b266d9eae8d1544371f00cef23fa701fcc7..fc70b304dd5d8c05823386fa68991e7fb2c0ad63 100644
--- a/src/main/java/org/eclipsefoundation/git/eca/resource/WebhooksResource.java
+++ b/src/main/java/org/eclipsefoundation/git/eca/resource/WebhooksResource.java
@@ -19,6 +19,7 @@ import javax.ws.rs.core.Response;
 import org.eclipsefoundation.core.model.RequestWrapper;
 import org.eclipsefoundation.git.eca.api.models.SystemHook;
 import org.eclipsefoundation.git.eca.namespace.EventType;
+import org.eclipsefoundation.git.eca.namespace.WebhookHeaders;
 import org.eclipsefoundation.git.eca.service.SystemHookService;
 import org.jboss.resteasy.annotations.jaxrs.HeaderParam;
 import org.slf4j.Logger;
@@ -41,7 +42,7 @@ public class WebhooksResource {
 
     @POST
     @Path("system")
-    public Response processGitlabHook(@HeaderParam("X-Gitlab-Event") String eventHeader, String jsonBody) {
+    public Response processGitlabHook(@HeaderParam(WebhookHeaders.GITLAB_EVENT) String eventHeader, String jsonBody) {
         // Do not process if header is incorrect
         if (!"system hook".equalsIgnoreCase(eventHeader)) {
             return Response.ok().build();
diff --git a/src/main/java/org/eclipsefoundation/git/eca/resource/mapper/BadRequestMapper.java b/src/main/java/org/eclipsefoundation/git/eca/resource/mapper/BadRequestMapper.java
deleted file mode 100644
index 7a276b81af1c1d94f3457ef9212f51180b2edd67..0000000000000000000000000000000000000000
--- a/src/main/java/org/eclipsefoundation/git/eca/resource/mapper/BadRequestMapper.java
+++ /dev/null
@@ -1,37 +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: Zachary Sabourin <zachary.sabourin@eclipse-foundation.org>
-*
-* SPDX-License-Identifier: EPL-2.0
-**********************************************************************/
-package org.eclipsefoundation.git.eca.resource.mapper;
-
-import javax.ws.rs.BadRequestException;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.Response.Status;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-import org.eclipsefoundation.core.model.Error;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Creates human legible error responses in the case of BadRequestExceptions.
- */
-@Provider
-public class BadRequestMapper implements ExceptionMapper<BadRequestException> {
-
-    private static final Logger LOGGER = LoggerFactory.getLogger(BadRequestMapper.class);
-
-    @Override
-    public Response toResponse(BadRequestException exception) {
-        LOGGER.error(exception.getMessage());
-        return new Error(Status.BAD_REQUEST, exception.getMessage()).asResponse();
-    }
-}
diff --git a/src/main/java/org/eclipsefoundation/git/eca/resource/mapper/RuntimeMapper.java b/src/main/java/org/eclipsefoundation/git/eca/resource/mapper/RuntimeMapper.java
deleted file mode 100644
index 39c317dbe7bb8b7bb9e97ec64331bbde9dbf87f6..0000000000000000000000000000000000000000
--- a/src/main/java/org/eclipsefoundation/git/eca/resource/mapper/RuntimeMapper.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*********************************************************************
-* Copyright (c) 2019 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.resource.mapper;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.Response.Status;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Catch-all exception mapper to ensure that any error thrown by the service
- * will log the error and quit out safely while limiting the response to a
- * simple error.
- * 
- * @author Martin Lowe
- *
- */
-@Provider
-public class RuntimeMapper implements ExceptionMapper<RuntimeException> {
-	private static final Logger LOGGER = LoggerFactory.getLogger(RuntimeMapper.class);
-
-	@Override
-	public Response toResponse(RuntimeException exception) {
-		LOGGER.error(exception.getMessage(), exception);
-		// return an empty response with a server error response
-		return Response.status(Status.INTERNAL_SERVER_ERROR).build();
-	}
-
-}
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 b26a3fb815105bcd64ab33f3b4330fc74ddae726..ff23076451d0c2ec7e6eddf2cdfe369825adf06a 100644
--- a/src/main/java/org/eclipsefoundation/git/eca/service/ValidationService.java
+++ b/src/main/java/org/eclipsefoundation/git/eca/service/ValidationService.java
@@ -15,6 +15,7 @@ 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;
@@ -98,7 +99,7 @@ public interface ValidationService {
         try {
             return HexConverter.convertToHexString(MessageDigest.getInstance("MD5").digest(sb.toString().getBytes()));
         } catch (NoSuchAlgorithmException e) {
-            throw new RuntimeException("Error while encoding request fingerprint - couldn't find MD5 algorithm.");
+            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/impl/DefaultGithubApplicationService.java b/src/main/java/org/eclipsefoundation/git/eca/service/impl/DefaultGithubApplicationService.java
index 9027ca48dbe1a08ad8472ea7ee1ed563d41df7b0..0875d375771e62c7392c333220efc39fc448eb58 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
@@ -24,6 +24,7 @@ import javax.ws.rs.core.MultivaluedMap;
 import org.eclipse.microprofile.config.inject.ConfigProperty;
 import org.eclipse.microprofile.context.ManagedExecutor;
 import org.eclipse.microprofile.rest.client.inject.RestClient;
+import org.eclipsefoundation.core.exception.ApplicationException;
 import org.eclipsefoundation.core.service.APIMiddleware;
 import org.eclipsefoundation.core.service.CachingService;
 import org.eclipsefoundation.git.eca.api.GithubAPI;
@@ -94,7 +95,7 @@ public class DefaultGithubApplicationService implements GithubApplicationService
             Thread.currentThread().interrupt();
         } catch (Exception e) {
             // rewrap exception and throw
-            throw new RuntimeException(e);
+            throw new ApplicationException("Thread interrupted while building repository cache, no entries will be available for current call", e);
         }
         return new MultivaluedMapImpl<>();
     }
diff --git a/src/main/resources/templates/simple_fingerprint_ui.html b/src/main/resources/templates/simple_fingerprint_ui.html
index 358cefb5d70336fab754feb06d6adbe388cc468e..8b861a0c59b5da313eb9951e976d15a88c6715d6 100644
--- a/src/main/resources/templates/simple_fingerprint_ui.html
+++ b/src/main/resources/templates/simple_fingerprint_ui.html
@@ -74,7 +74,7 @@
             </li>
             {/if}
           </ul>
-          <a href="{repoUrl}" target="_blank" class="btn btn-primary margin-top-10">Project repository</a>
+          <a href="{repoUrl}" target="_blank" rel="noopener" class="btn btn-primary margin-top-10">Project repository</a>
         </div>
       </div>
       {#if statuses.getErrorCount > 0}
@@ -153,7 +153,7 @@
       <div>
         <form id="git-eca-hook-revalidation" data-request-number="{pullRequestNumber}" data-request-repo="{fullRepoName}" data-request-installation="{installationId}">
           <div class="captcha">
-            <div class="h-captcha" data-sitekey="{config:['eclipse.hcaptcha.sitekey']}"></div>
+            <div class="h-captcha" data-sitekey="{config:['eclipse.hcaptcha.site-key']}"></div>
           </div>
           <button class="btn-success margin-top-10 btn form-submit" type="submit">Revalidate</button>
         </form>
@@ -161,7 +161,7 @@
       {/if}
     </section>
 
-    <aside id="main-sidebar-secondy" role="complementary" class="col-md-6 col-sm-8 margin-bottom-60">
+    <aside id="main-sidebar-secondy" role="complementary" class="col-md-6 col-sm-8 margin-bottom-60" aria-label="eclipse-contributor-agreement">
       <div class="region region-sidebar-second solstice-region-element-count-2">
         <section id="block-site-login-eclipse-eca-sle-eca-lookup-tool"
           class="block block-site-login-eclipse-eca block-region-sidebar-second solstice-block solstice-block-default solstice-block-white-bg block-sle-eca-lookup-tool clearfix">
@@ -181,7 +181,7 @@
       <section id="block-eclipse-api-github-eclipse-api-github-links"
         class="block block-eclipse-api-github contextual-links-region block-region-sidebar-second solstice-block block-eclipse-api-github-links clearfix">
         <div class="block-content">
-          <aside class="main-sidebar-default-margin" id="main-sidebar">
+          <aside class="main-sidebar-default-margin" id="main-sidebar" aria-label="eclipse-contributor-agreement-links">
             <ul id="leftnav" class="ul-left-nav fa-ul hidden-print">
               <li class="separator"><a class="separator" href="https://www.eclipse.org/legal/ECA.php"> ECA </a></li>
               <li><i class="fa fa-caret-right fa-fw" aria-hidden="true"></i> <a href="https://accounts.eclipse.org/user/eca"
diff --git a/src/test/java/org/eclipsefoundation/git/eca/resource/GithubWebhooksResourceTest.java b/src/test/java/org/eclipsefoundation/git/eca/resource/GithubWebhooksResourceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..45ff97b3c39d9430712a8becb3a09e7aad2f5bc5
--- /dev/null
+++ b/src/test/java/org/eclipsefoundation/git/eca/resource/GithubWebhooksResourceTest.java
@@ -0,0 +1,79 @@
+/*********************************************************************
+* 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: Zachary Sabourin <zachary.sabourin@eclipse-foundation.org>
+*
+* SPDX-License-Identifier: EPL-2.0
+**********************************************************************/
+package org.eclipsefoundation.git.eca.resource;
+
+import java.util.Map;
+import java.util.Optional;
+
+import javax.inject.Inject;
+
+import org.eclipsefoundation.core.exception.ApplicationException;
+import org.eclipsefoundation.git.eca.api.models.GithubWebhookRequest;
+import org.eclipsefoundation.git.eca.api.models.GithubWebhookRequest.Installation;
+import org.eclipsefoundation.git.eca.api.models.GithubWebhookRequest.PullRequest;
+import org.eclipsefoundation.git.eca.api.models.GithubWebhookRequest.PullRequestHead;
+import org.eclipsefoundation.git.eca.api.models.GithubWebhookRequest.Repository;
+import org.eclipsefoundation.git.eca.namespace.WebhookHeaders;
+import org.eclipsefoundation.testing.helpers.TestCaseHelper;
+import org.eclipsefoundation.testing.models.EndpointTestBuilder;
+import org.junit.jupiter.api.Test;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import io.quarkus.test.junit.QuarkusTest;
+
+@QuarkusTest
+class GithubWebhooksResourceTest {
+    private static final String GH_WEBHOOK_BASE_URL = "/webhooks/github";
+
+    @Inject
+    ObjectMapper om;
+
+    @Test
+    void testInvalidEventType() {
+        EndpointTestBuilder.from(TestCaseHelper.prepareTestCase(GH_WEBHOOK_BASE_URL, new String[] {}, null)
+                .setHeaderParams(Optional.of(Map.of(WebhookHeaders.GITHUB_EVENT, "nope"))).build()).doPost()
+                .run();
+    }
+
+    @Test
+    void testGHWebhook_success() {
+        EndpointTestBuilder
+                .from(TestCaseHelper
+                        .prepareTestCase(GH_WEBHOOK_BASE_URL, new String[] {}, null)
+                        .setHeaderParams(Optional.of(Map.of(WebhookHeaders.GITHUB_DELIVERY, "id-1", WebhookHeaders.GITHUB_EVENT, "pull_request")))
+                        .build())
+                .doPost(createGHWebhook())
+                .run();
+    }
+
+    private String createGHWebhook() {
+        try {
+            return om.writeValueAsString(GithubWebhookRequest.builder()
+                    .setInstallation(Installation.builder().setId("install-id").build())
+                    .setPullRequest(PullRequest
+                            .builder()
+                            .setNumber(42)
+                            .setHead(PullRequestHead.builder().setSha("sha-1234").build())
+                            .setState("open")
+                            .build())
+                    .setRepository(Repository
+                            .builder()
+                            .setFullName("eclipsefdn/sample")
+                            .setHtmlUrl("http://www.github.com/eclipsefdn/sample")
+                            .build())
+                    .build());
+        } catch (Exception e) {
+            throw new ApplicationException("Error converting Hook to JSON");
+        }
+    }
+}
diff --git a/src/test/java/org/eclipsefoundation/git/eca/resource/ReportsResourceTest.java b/src/test/java/org/eclipsefoundation/git/eca/resource/ReportsResourceTest.java
index e329ce2f3377814f7846b100a3fc55afdd682e1b..8def7dcf42cb21cacafe2cbd42a365eb1537380a 100644
--- a/src/test/java/org/eclipsefoundation/git/eca/resource/ReportsResourceTest.java
+++ b/src/test/java/org/eclipsefoundation/git/eca/resource/ReportsResourceTest.java
@@ -97,16 +97,6 @@ class ReportsResourceTest {
         RestAssuredTemplates.testGet_validateResponseFormat(GET_REPORT_SUCCESS_CASE);
     }
 
-    @Test
-    void getPrivProjReport_failure_invalidResponseFormat() {
-        RestAssuredTemplates
-                .testGet(TestCaseHelper
-                        .prepareTestCase(REPORTS_PROJECTS_URL, new String[] { VALID_TEST_ACCESS_KEY }, null)
-                        .setResponseContentType(ContentType.TEXT)
-                        .setStatusCode(500)
-                        .build());
-    }
-
     @Test
     void getPrivProjReport_failure_badAccessKey() {
         RestAssuredTemplates.testGet(GET_REPORT_BAD_ACCESS_KEY);
diff --git a/src/test/java/org/eclipsefoundation/git/eca/resource/StatusResourceTest.java b/src/test/java/org/eclipsefoundation/git/eca/resource/StatusResourceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..f6e850d2799d4acb7c52644a9066bd74cb1b6714
--- /dev/null
+++ b/src/test/java/org/eclipsefoundation/git/eca/resource/StatusResourceTest.java
@@ -0,0 +1,78 @@
+/*********************************************************************
+* 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: Zachary Sabourin <zachary.sabourin@eclipse-foundation.org>
+*
+* SPDX-License-Identifier: EPL-2.0
+**********************************************************************/
+package org.eclipsefoundation.git.eca.resource;
+
+import java.util.Collections;
+import java.util.Map;
+
+import org.eclipsefoundation.git.eca.test.namespaces.SchemaNamespaceHelper;
+import org.eclipsefoundation.testing.helpers.TestCaseHelper;
+import org.eclipsefoundation.testing.models.EndpointTestBuilder;
+import org.eclipsefoundation.testing.templates.RestAssuredTemplates.EndpointTestCase;
+import org.junit.jupiter.api.Test;
+
+import io.quarkus.test.junit.QuarkusTest;
+import io.restassured.http.ContentType;
+
+@QuarkusTest
+class StatusResourceTest {
+    public static final String STATUS_BASE_URL = "/eca/status";
+    public static final String FINGERPRINT_STATUS_BASE_URL = STATUS_BASE_URL + "/{fingerprint}";
+    public static final String FINGERPRINT_STATUS_UI_BASE_URL = FINGERPRINT_STATUS_BASE_URL + "/ui";
+
+    private static final String VALID_FINGERPRINT = "957706b0f31e0ccfc5287c0ebc62dc79";
+    private static final String INVALID_FINGERPRINT = "nope";
+
+    public static final EndpointTestCase GET_STATUS_SUCCESS_CASE = TestCaseHelper
+            .buildSuccessCase(FINGERPRINT_STATUS_BASE_URL, new String[] { VALID_FINGERPRINT },
+                    SchemaNamespaceHelper.COMMIT_VALIDATION_STATUSES_SCHEMA);
+
+    public static final EndpointTestCase GET_STATUS_UI_NOT_FOUND_CASE = TestCaseHelper
+            .prepareTestCase(FINGERPRINT_STATUS_UI_BASE_URL, new String[] { INVALID_FINGERPRINT }, null)
+            .setResponseContentType(ContentType.HTML)
+            .setStatusCode(404).build();
+
+    @Test
+    void testGetValidationStatus_success_validFormatAndSchema() {
+        EndpointTestBuilder.from(GET_STATUS_SUCCESS_CASE).doGet().andCheckSchema().andCheckFormat().run();
+    }
+
+    @Test
+    void testGetValidationStatus_success_invalidFingerprint() {
+        // invalid/not found fingerprint returns 200 with an empty list
+        EndpointTestBuilder
+                .from(TestCaseHelper
+                        .prepareTestCase(FINGERPRINT_STATUS_BASE_URL, new String[] { INVALID_FINGERPRINT }, null)
+                        .setBodyValidationParams(Map.of("", Collections.emptyList())).build())
+                .andCheckBodyParams()
+                .doGet()
+                .run();
+    }
+
+    @Test
+    void testGetValidationStatusUi_success() {
+        EndpointTestBuilder
+                .from(TestCaseHelper
+                        .prepareTestCase(FINGERPRINT_STATUS_UI_BASE_URL, new String[] { VALID_FINGERPRINT }, null)
+                        .setResponseContentType(ContentType.HTML).build())
+                .doGet().run();
+    }
+
+    @Test
+    void testGetValidationStatusUi_failure_notFound() {
+        EndpointTestBuilder
+                .from(TestCaseHelper
+                        .prepareTestCase(FINGERPRINT_STATUS_UI_BASE_URL, new String[] { INVALID_FINGERPRINT }, null)
+                        .setResponseContentType(ContentType.HTML).setStatusCode(404).build())
+                .doGet().run();
+    }
+}
diff --git a/src/test/java/org/eclipsefoundation/git/eca/resource/ValidationResourceTest.java b/src/test/java/org/eclipsefoundation/git/eca/resource/ValidationResourceTest.java
index 1c2a56a055a9acecaadc3c79491193ac2346fd8c..ba99ddc39d06d1a1f94acf00cc3bd5af1f8b23bf 100644
--- a/src/test/java/org/eclipsefoundation/git/eca/resource/ValidationResourceTest.java
+++ b/src/test/java/org/eclipsefoundation/git/eca/resource/ValidationResourceTest.java
@@ -25,6 +25,7 @@ import java.util.UUID;
 
 import javax.inject.Inject;
 
+import org.eclipsefoundation.core.exception.ApplicationException;
 import org.eclipsefoundation.core.service.CachingService;
 import org.eclipsefoundation.git.eca.model.Commit;
 import org.eclipsefoundation.git.eca.model.GitUser;
@@ -151,7 +152,7 @@ class ValidationResourceTest {
         try {
             in = json.writeValueAsString(VALIDATE_SUCCESS_BODY);
         } catch (JsonProcessingException e) {
-            throw new RuntimeException(e);
+            throw new ApplicationException("Error converting body to JSON format", e);
         }
 
         Assertions.assertTrue(matchesJsonSchemaInClasspath(SchemaNamespaceHelper.VALIDATION_REQUEST_SCHEMA_PATH).matches(in));
@@ -423,6 +424,59 @@ class ValidationResourceTest {
                         createGitHubRequest(true, "http://www.github.com/eclipsefdn-tck/tck-ignored", Arrays.asList(c1)));
     }
 
+    @Test
+    void testValidate_success_noCommits() {
+
+        // We do not block contributions to non-project repos
+        RestAssuredTemplates
+                .testPost(VALIDATE_SUCCESS_CASE,
+                        createGitHubRequest(true, "http://www.github.com/eclipsefdn/prototype.git",
+                                Collections.emptyList()));
+
+        // Strictmode shouldn't affect the result
+        RestAssuredTemplates
+                .testPost(VALIDATE_SUCCESS_CASE,
+                        createGitHubRequest(false, "http://www.github.com/eclipsefdn/prototype.git",
+                                Collections.emptyList()));
+    }
+
+    @Test
+    void testValidate_failure_noRepoUrl() {
+        Commit c1 = createStandardUsercommit(USER_WIZARD, USER_NEWBIE);
+
+        // We do not block contributions to non-project repos
+        RestAssuredTemplates
+                .testPost(VALIDATE_SUCCESS_CASE, createGitHubRequest(true, "", Arrays.asList(c1)));
+
+        // Strictmode shouldn't affect the result
+        RestAssuredTemplates
+                .testPost(VALIDATE_SUCCESS_CASE,
+                        createGitHubRequest(false, "", Arrays.asList(c1)));
+    }
+
+    @Test
+    void testValidate_failure_noProvider() {
+        Commit c1 = createStandardUsercommit(USER_WIZARD, USER_NEWBIE);
+
+        // Request with no provider set
+        ValidationRequest req = ValidationRequest
+                .builder()
+                .setStrictMode(true)
+                .setRepoUrl(URI.create("http://www.github.com/eclipsefdn/prototype.git"))
+                .setCommits(Arrays.asList(c1))
+                .build();
+
+        // We do not block contributions to non-project repos
+        RestAssuredTemplates
+                .testPost(VALIDATE_SUCCESS_CASE, req);
+
+        req = req.toBuilder().setStrictMode(false).build();
+
+        // Strictmode shouldn't affect the result
+        RestAssuredTemplates
+                .testPost(VALIDATE_SUCCESS_CASE, req);
+    }
+
     /*
      * BOT ACCESS TESTS
      */
diff --git a/src/test/java/org/eclipsefoundation/git/eca/resource/WebhoooksResourceTest.java b/src/test/java/org/eclipsefoundation/git/eca/resource/WebhooksResourceTest.java
similarity index 85%
rename from src/test/java/org/eclipsefoundation/git/eca/resource/WebhoooksResourceTest.java
rename to src/test/java/org/eclipsefoundation/git/eca/resource/WebhooksResourceTest.java
index 23a1d312f08ed6993510273de208699eef1c70fa..857e80d80916c7fa264b03652c1458e1f1148b74 100644
--- a/src/test/java/org/eclipsefoundation/git/eca/resource/WebhoooksResourceTest.java
+++ b/src/test/java/org/eclipsefoundation/git/eca/resource/WebhooksResourceTest.java
@@ -16,6 +16,9 @@ import java.util.Arrays;
 import java.util.Map;
 import java.util.Optional;
 
+import javax.inject.Inject;
+
+import org.eclipsefoundation.core.exception.ApplicationException;
 import org.eclipsefoundation.git.eca.api.models.SystemHook;
 import org.eclipsefoundation.git.eca.api.models.SystemHook.Owner;
 import org.eclipsefoundation.testing.helpers.TestCaseHelper;
@@ -23,10 +26,12 @@ import org.eclipsefoundation.testing.templates.RestAssuredTemplates;
 import org.eclipsefoundation.testing.templates.RestAssuredTemplates.EndpointTestCase;
 import org.junit.jupiter.api.Test;
 
+import com.fasterxml.jackson.databind.ObjectMapper;
+
 import io.quarkus.test.junit.QuarkusTest;
 
 @QuarkusTest
-class WebhoooksResourceTest {
+class WebhooksResourceTest {
     public static final String WEBHOOKS_BASE_URL = "/webhooks";
     public static final String GITLAB_HOOK_URL = WEBHOOKS_BASE_URL + "/gitlab/system";
 
@@ -124,33 +129,44 @@ class WebhoooksResourceTest {
     public static final EndpointTestCase CASE_HOOK_MISSING_HEADER = TestCaseHelper.buildSuccessCase(
             GITLAB_HOOK_URL, new String[] {}, null);
 
+    @Inject
+    ObjectMapper om;
+
     @Test
     void processCreateHook_success() {
-        RestAssuredTemplates.testPost(CASE_HOOK_SUCCESS, PROJECT_CREATE_HOOK_VALID);
+        RestAssuredTemplates.testPost(CASE_HOOK_SUCCESS, convertHookToJson(PROJECT_CREATE_HOOK_VALID));
     }
 
     @Test
     void processDeleteHook_success() {
-        RestAssuredTemplates.testPost(CASE_HOOK_SUCCESS, PROJECT_DESTROY_HOOK_VALID);
+        RestAssuredTemplates.testPost(CASE_HOOK_SUCCESS, convertHookToJson(PROJECT_DESTROY_HOOK_VALID));
     }
 
     @Test
     void processRenameHook_success() {
-        RestAssuredTemplates.testPost(CASE_HOOK_SUCCESS, PROJECT_RENAME_HOOK_VALID);
+        RestAssuredTemplates.testPost(CASE_HOOK_SUCCESS, convertHookToJson(PROJECT_RENAME_HOOK_VALID));
     }
 
     @Test
     void processCreateHook_success_untrackedEvent() {
-        RestAssuredTemplates.testPost(CASE_HOOK_SUCCESS, HOOK_NOT_TRACKED);
+        RestAssuredTemplates.testPost(CASE_HOOK_SUCCESS, convertHookToJson(HOOK_NOT_TRACKED));
     }
 
     @Test
     void processCreateHook_success_missingEventName() {
-        RestAssuredTemplates.testPost(CASE_HOOK_SUCCESS, HOOK_MISSING_EVENT);
+        RestAssuredTemplates.testPost(CASE_HOOK_SUCCESS, convertHookToJson(HOOK_MISSING_EVENT));
     }
 
     @Test
     void processCreateHook_success_missingHeaderParam() {
-        RestAssuredTemplates.testPost(CASE_HOOK_MISSING_HEADER, PROJECT_CREATE_HOOK_VALID);
+        RestAssuredTemplates.testPost(CASE_HOOK_MISSING_HEADER, convertHookToJson(PROJECT_CREATE_HOOK_VALID));
+    }
+
+    private String convertHookToJson(SystemHook hook) {
+        try {
+            return om.writeValueAsString(hook);
+        } catch (Exception e) {
+            throw new ApplicationException("Error converting Hook to JSON");
+        }
     }
 }
diff --git a/src/test/java/org/eclipsefoundation/git/eca/test/api/MockGithubAPI.java b/src/test/java/org/eclipsefoundation/git/eca/test/api/MockGithubAPI.java
new file mode 100644
index 0000000000000000000000000000000000000000..441d15d6b65292664fa1460dae8de0c556d9563e
--- /dev/null
+++ b/src/test/java/org/eclipsefoundation/git/eca/test/api/MockGithubAPI.java
@@ -0,0 +1,106 @@
+/*********************************************************************
+* 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: Zachary Sabourin <zachary.sabourin@eclipse-foundation.org>
+*
+* SPDX-License-Identifier: EPL-2.0
+**********************************************************************/
+package org.eclipsefoundation.git.eca.test.api;
+
+import java.time.LocalDateTime;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.ws.rs.core.Response;
+
+import org.eclipse.microprofile.rest.client.inject.RestClient;
+import org.eclipsefoundation.core.service.APIMiddleware.BaseAPIParameters;
+import org.eclipsefoundation.git.eca.api.GithubAPI;
+import org.eclipsefoundation.git.eca.api.models.GithubAccessToken;
+import org.eclipsefoundation.git.eca.api.models.GithubCommit;
+import org.eclipsefoundation.git.eca.api.models.GithubCommit.CommitData;
+import org.eclipsefoundation.git.eca.api.models.GithubCommit.GitCommitUser;
+import org.eclipsefoundation.git.eca.api.models.GithubCommit.GithubCommitUser;
+import org.eclipsefoundation.git.eca.api.models.GithubCommitStatusRequest;
+import org.eclipsefoundation.git.eca.api.models.GithubWebhookRequest.PullRequest;
+
+import io.quarkus.test.Mock;
+
+@Mock
+@RestClient
+@ApplicationScoped
+public class MockGithubAPI implements GithubAPI {
+
+    Map<String, Map<Integer, List<GithubCommit>>> commits;
+    Map<String, Map<String, String>> commitStatuses;
+
+    public MockGithubAPI() {
+        this.commitStatuses = new HashMap<>();
+        this.commits = new HashMap<>();
+        this.commits.put("eclipsefdn/sample",
+                Map.of(42,
+                        Arrays.asList(GithubCommit.builder()
+                                .setSha("sha-1234")
+                                .setAuthor(GithubCommitUser.builder().setLogin("testuser").build())
+                                .setCommitter(GithubCommitUser.builder().setLogin("testuser").build())
+                                .setParents(Collections.emptyList())
+                                .setCommit(CommitData.builder()
+                                        .setAuthor(
+                                                GitCommitUser.builder().setName("The Wizard")
+                                                        .setEmail("code.wiz@important.co")
+                                                        .build())
+                                        .setCommitter(
+                                                GitCommitUser.builder().setName("The Wizard")
+                                                        .setEmail("code.wiz@important.co")
+                                                        .build())
+                                        .build())
+                                .build())));
+    }
+
+    @Override
+    public PullRequest getPullRequest(String bearer, String apiVersion, String repoFull, int pullNumber) {
+        return PullRequest.builder().build();
+    }
+
+    @Override
+    public Response getCommits(String bearer, String apiVersion, String repoFull, int pullNumber) {
+        List<GithubCommit> results = commits.get(repoFull).get(pullNumber);
+        if (results == null && !results.isEmpty()) {
+            return Response.status(404).build();
+        }
+        return Response.ok(results).build();
+    }
+
+    @Override
+    public Response updateStatus(String bearer, String apiVersion, String repoFull, String prHeadSha,
+            GithubCommitStatusRequest commitStatusUpdate) {
+        commitStatuses.computeIfAbsent(repoFull, m -> new HashMap<>()).merge(prHeadSha, commitStatusUpdate.getState(),
+                (k, v) -> v);
+        return Response.ok().build();
+    }
+
+    @Override
+    public Response getInstallations(BaseAPIParameters params, String bearer) {
+        throw new UnsupportedOperationException("Unimplemented method 'getInstallations'");
+    }
+
+    @Override
+    public GithubAccessToken getNewAccessToken(String bearer, String apiVersion, String installationId) {
+        return GithubAccessToken.builder()
+                .setToken("gh-token-" + installationId)
+                .setExpiresAt(LocalDateTime.now().plusHours(1L)).build();
+    }
+
+    @Override
+    public Response getInstallationRepositories(BaseAPIParameters params, String bearer) {
+        throw new UnsupportedOperationException("Unimplemented method 'getInstallationRepositories'");
+    }
+}
diff --git a/src/test/java/org/eclipsefoundation/git/eca/test/api/MockGitlabAPI.java b/src/test/java/org/eclipsefoundation/git/eca/test/api/MockGitlabAPI.java
index 4062fa8b826b0301cd9de1abeec44ce01b9a1b3c..1252307f7caa1b63b875050409cd6c447470114a 100644
--- a/src/test/java/org/eclipsefoundation/git/eca/test/api/MockGitlabAPI.java
+++ b/src/test/java/org/eclipsefoundation/git/eca/test/api/MockGitlabAPI.java
@@ -11,6 +11,7 @@
 **********************************************************************/
 package org.eclipsefoundation.git.eca.test.api;
 
+import java.time.ZonedDateTime;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -41,16 +42,22 @@ public class MockGitlabAPI implements GitlabAPI {
                 GitlabProjectResponse.builder()
                         .setId(69)
                         .setCreatorId(1)
+                        .setPathWithNamespace("namespace/path")
+                        .setCreatedAt(ZonedDateTime.now())
                         .build(),
                 GitlabProjectResponse.builder()
                         .setId(42)
                         .setCreatorId(55)
                         .setForkedFromProject(ForkedProject.builder().setId(41).build())
+                        .setPathWithNamespace("namespace/path")
+                        .setCreatedAt(ZonedDateTime.now())
                         .build(),
                 GitlabProjectResponse.builder()
                         .setId(95)
                         .setCreatorId(33)
                         .setForkedFromProject(ForkedProject.builder().setId(69).build())
+                        .setPathWithNamespace("namespace/path")
+                        .setCreatedAt(ZonedDateTime.now())
                         .build()));
 
         users = new ArrayList<>();
diff --git a/src/test/java/org/eclipsefoundation/git/eca/test/helper/TestJWTHelper.java b/src/test/java/org/eclipsefoundation/git/eca/test/helper/TestJWTHelper.java
new file mode 100644
index 0000000000000000000000000000000000000000..369f93cbb48a8e6b480dd42693320253918d9912
--- /dev/null
+++ b/src/test/java/org/eclipsefoundation/git/eca/test/helper/TestJWTHelper.java
@@ -0,0 +1,33 @@
+package org.eclipsefoundation.git.eca.test.helper;
+
+import javax.inject.Singleton;
+
+import org.eclipse.microprofile.config.inject.ConfigProperty;
+import org.eclipse.microprofile.rest.client.inject.RestClient;
+import org.eclipsefoundation.git.eca.api.GithubAPI;
+import org.eclipsefoundation.git.eca.api.models.GithubAccessToken;
+import org.eclipsefoundation.git.eca.helper.JwtHelper;
+
+import io.quarkus.cache.CacheResult;
+import io.quarkus.test.Mock;
+
+@Singleton
+@Mock
+public class TestJWTHelper extends JwtHelper {
+
+    @Override
+    public String getGhBearerString(String installationId) {
+        return "Bearer " + getGithubAccessToken(installationId).getToken();
+    }
+
+    @CacheResult(cacheName = "accesstoken")
+    @Override
+    public GithubAccessToken getGithubAccessToken(String installationId) {
+        return ghApi.getNewAccessToken("Bearer " + generateJwt(), apiVersion, installationId);
+    }
+
+    @Override
+    public String generateJwt() {
+        return "jwt-test";
+    }
+}
diff --git a/src/test/java/org/eclipsefoundation/git/eca/test/namespaces/SchemaNamespaceHelper.java b/src/test/java/org/eclipsefoundation/git/eca/test/namespaces/SchemaNamespaceHelper.java
index 6bf874f9d757abd6baec2af53ecff7d31c05bf48..838fc9bf55a42c06757a6299dd0697ebdf51c649 100644
--- a/src/test/java/org/eclipsefoundation/git/eca/test/namespaces/SchemaNamespaceHelper.java
+++ b/src/test/java/org/eclipsefoundation/git/eca/test/namespaces/SchemaNamespaceHelper.java
@@ -25,5 +25,10 @@ public final class SchemaNamespaceHelper {
 	public static final String PRIVATE_PROJECT_EVENTS_SCHEMA_PATH = BASE_SCHEMAS_PATH + "private-project-events"
 			+ BASE_SCHEMAS_PATH_SUFFIX;
 
+	public static final String COMMIT_VALIDATION_STATUS_SCHEMA = BASE_SCHEMAS_PATH + "commit-validation-status"
+			+ BASE_SCHEMAS_PATH_SUFFIX;
+	public static final String COMMIT_VALIDATION_STATUSES_SCHEMA = BASE_SCHEMAS_PATH + "commit-validation-statuses"
+			+ BASE_SCHEMAS_PATH_SUFFIX;
+
 	public static final String ERROR_SCHEMA_PATH = BASE_SCHEMAS_PATH + "error" + BASE_SCHEMAS_PATH_SUFFIX;
 }
diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties
index b468fd8f1c70edda794f5b7ff65f270b7ee6d2e6..ed2bc8fb08d1992cd53873ad2ad94b65c3eb3d10 100644
--- a/src/test/resources/application.properties
+++ b/src/test/resources/application.properties
@@ -36,4 +36,7 @@ eclipse.git-eca.mail.allow-list=noreply@github.com
 eclipse.git-eca.reports.access-key=samplekey
 
 ## Misc
-eclipse.gitlab.access-token=token_val
\ No newline at end of file
+eclipse.gitlab.access-token=token_val
+
+## Disable private project scan in test mode
+eclipse.scheduled.private-project.enabled=false
\ No newline at end of file
diff --git a/src/test/resources/database/default/V1.0.0__default.sql b/src/test/resources/database/default/V1.0.0__default.sql
index 09fa5c3dffe1f162ea9e86bf5c352a5055a9e41f..100590d363360f140356726c5d366cfe12a9e56d 100644
--- a/src/test/resources/database/default/V1.0.0__default.sql
+++ b/src/test/resources/database/default/V1.0.0__default.sql
@@ -51,7 +51,7 @@ INSERT INTO PrivateProjectEvent(userId, projectId, projectPath, ef_username, par
 CREATE TABLE GithubWebhookTracking (
   id SERIAL NOT NULL,
   lastKnownState varchar(63) NOT NULL,
-  deliveryId varchar(63) NOT NULL,
+  installationId varchar(63) NOT NULL,
   headSha varchar(63) NOT NULL,
   repositoryFullName varchar(127) NOT NULL,
   pullRequestNumber int NOT NULL,