From aa3c9e62d8cf2c32ec3d8795a12dc7c34df64571 Mon Sep 17 00:00:00 2001
From: Martin Lowe <martin.lowe@eclipse-foundation.org>
Date: Thu, 9 Mar 2023 14:25:38 -0500
Subject: [PATCH 1/3] Iss #123 - Update status UI page to handle revalidation
 more intuitively

Adds blocking form processing on the page for revalidation form so that
we can more naturally handle errors.

Resolves #123
---
 pom.xml                                       |  4 +-
 .../templates/simple_fingerprint_ui.html      | 40 ++++++++++++++++++-
 2 files changed, 40 insertions(+), 4 deletions(-)

diff --git a/pom.xml b/pom.xml
index 3baf3ec6..9db3d20b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
   <artifactId>git-eca</artifactId>
   <version>1.1.0</version>
   <properties>
-    <eclipse-api-version>0.6.10</eclipse-api-version>
+    <eclipse-api-version>0.7.1</eclipse-api-version>
     <compiler-plugin.version>3.8.1</compiler-plugin.version>
     <maven.compiler.parameters>true</maven.compiler.parameters>
     <maven.compiler.source>11</maven.compiler.source>
@@ -14,7 +14,7 @@
     <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
     <quarkus.platform.artifact-id>quarkus-universe-bom</quarkus.platform.artifact-id>
     <quarkus.platform.group-id>io.quarkus</quarkus.platform.group-id>
-    <quarkus.platform.version>2.9.2.Final</quarkus.platform.version>
+    <quarkus.platform.version>2.14.2.Final</quarkus.platform.version>
     <surefire-plugin.version>2.22.1</surefire-plugin.version>
     <auto-value.version>1.8.2</auto-value.version>
     <org.mapstruct.version>1.4.1.Final</org.mapstruct.version>
diff --git a/src/main/resources/templates/simple_fingerprint_ui.html b/src/main/resources/templates/simple_fingerprint_ui.html
index 497698c4..6347fc72 100644
--- a/src/main/resources/templates/simple_fingerprint_ui.html
+++ b/src/main/resources/templates/simple_fingerprint_ui.html
@@ -1,4 +1,6 @@
-{#include eclipse_header /}
+{#include eclipse_header}
+  {#title}Git ECA Validation{/}
+{/include}
 {#include eclipse_breadcrumb /}
 {|<style>
   .panel.list-group>div {
@@ -140,7 +142,7 @@
       {/if}
       {#if statuses.0.provider == ProviderType:GITHUB}
       <div>
-        <form action="/git/webhooks/github/revalidate/{fingerprint}" method="POST">
+        <form id="git-eca-hook-revalidation" data-request-id="{fingerprint}">
           <div class="captcha">
             <div class="h-captcha" data-sitekey="{config:['eclipse.hcaptcha.sitekey']}"></div>
           </div>
@@ -218,8 +220,10 @@
         $newToast.fadeOut("slow");
       }, 10000);
     }
+    // set up accordion
     $('#accordion').on('hidden.bs.collapse', toggleIcon);
     $('#accordion').on('shown.bs.collapse', toggleIcon);
+    // bind to ECA status lookup submit
     document.getElementById("eclipse-eca-lookup-form").addEventListener("submit", function (e) {
       // don't submit the form as we will handle it w/ ajax
       e.preventDefault();
@@ -250,6 +254,38 @@
         }
       });
     });
+    
+    // Revalidation button binding
+    const revalidationForm = document.getElementById("git-eca-hook-revalidation");
+    if (revalidationForm !== null) {
+      revalidationForm.addEventListener("submit", function (e) {
+        // don't submit the form as we will handle it w/ ajax
+        e.preventDefault();
+        // grab the constants from the form and perform a check
+        const $form = $(e.target);
+        const $submitButton = $form.find('button');
+        // disable the button so that requests won't be spammed
+        $submitButton.attr("disabled", "disabled");
+        // use ajax to check the ECA status of the user
+        $.ajax({
+          url: `/git/webhooks/github/revalidate/${$form.data('request-id')}`,
+          data: $form.serialize(),
+          type: 'POST',
+          success: function (data, status, xhr) {
+            toast(`Revalidation complete! Forwarding to pull request.`, 'success');
+            window.location(xhr.getResponseHeader('Location'));
+          },
+          error: function (xhr) {
+            const json = JSON.parse(xhr.responseText);
+            console.log('Error encountered while revalidating: ' + json.message);
+            toast(json.message, 'danger');
+          },
+          complete: function () {
+            $submitButton.removeAttr("disabled");
+          }
+        });
+      });
+    }
   });
 
 </script>|}
-- 
GitLab


From 60d611d36f9afcd2f755738ff225fea7567b60bd Mon Sep 17 00:00:00 2001
From: Martin Lowe <martin.lowe@eclipse-foundation.org>
Date: Thu, 9 Mar 2023 15:14:15 -0500
Subject: [PATCH 2/3] Update revalidation response to not immediately redirect

Immediate redirects rightfully triggered CORS exceptions when used in
conjunction with AJAX. To get around this, we will return the new
location as the only property in the response and redirect manually on
success.
---
 spec/openapi.yaml                             | 112 ++++++++++++++++++
 .../git/eca/model/RevalidationResponse.java   |  44 +++++++
 .../eca/resource/GithubWebhooksResource.java  |   6 +-
 .../templates/simple_fingerprint_ui.html      |   8 +-
 4 files changed, 164 insertions(+), 6 deletions(-)
 create mode 100644 src/main/java/org/eclipsefoundation/git/eca/model/RevalidationResponse.java

diff --git a/spec/openapi.yaml b/spec/openapi.yaml
index 8759e982..93e49e58 100644
--- a/spec/openapi.yaml
+++ b/spec/openapi.yaml
@@ -51,6 +51,13 @@ paths:
           description: Error while retrieving data
 
   /eca/status/{fingerprint}/ui:
+    parameters:
+       - name: fingerprint
+         in: path
+         description: Unique ID for the request group
+         required: true
+         schema:
+            type: string
     get:
       summary: Historic ECA validation status in a HTML format
       description: Returns an HTMl page containing validation messages
@@ -76,6 +83,78 @@ paths:
         500:
           description: Error while retrieving data
 
+  /webhooks/github:
+    parameters:
+       - name: fingerprint
+         in: path
+         description: Unique ID for the request group
+         required: true
+         schema:
+            type: string
+    post:
+      tags:
+        - Github validation processing
+      summary: Github incoming hook event processing
+      description: Process incoming pull request hook events from Github
+      parameters:
+        - in: header
+          name: X-GitHub-Delivery
+          schema: 
+            type: string
+          required: true
+        - in: header
+          name: X-GitHub-Event
+          schema: 
+            type: string
+          required: true
+        - in: header
+          name: X-GitHub-Hook-ID
+          schema: 
+            type: string
+          required: true
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/SystemHook"
+      responses:
+        200:
+          description: Success
+        500:
+          description: Error while processing data
+  /webhooks/github/revalidate/{fingerprint}:
+    parameters:
+       - name: fingerprint
+         in: path
+         description: Unique ID for the request group
+         required: true
+         schema:
+            type: string
+    post:
+      tags:
+        - Github validation processing
+      summary: Gitlab webhook revalidation request
+      description: Process incoming system hooks from GitLab
+      parameters:
+        - in: header
+          name: X-Gitlab-Event
+          schema: 
+            type: string
+          required: true
+      requestBody:
+        content:
+          application/json:
+            schema:
+              $ref: "#/components/schemas/SystemHook"
+      responses:
+        200:
+          description: Success
+        400:
+          description: Bad request
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/Error"
   /webhooks/gitlab/system:
     post:
       tags:
@@ -429,6 +508,39 @@ components:
             - "null"
           description: the project deletion date if it was deleted
 
+    GithubWebhookEvent:
+      type: object
+      properties:
+        installation:
+          type: object
+          description: Information about the Github App installation making this request
+          properties:
+            id:
+              type: string
+              description: The ID of the app installation that is making the validation request on behalf of the repository/user.
+        repository:
+          type: object
+          description: Information about the repository that triggered this request
+          properties:
+            full_name:
+              type: string
+              description: The full name of the repository, including organization.
+            html_url:
+              type: string
+              description: The link to the repository the event was triggered by
+        pull_request:
+          type: object
+          description: Information on the pull request that triggered this workflow.
+          properties:
+            number:
+              type: int
+              description: The numeric ID of the pull request that triggered the flow
+            head:
+              type: object
+              properties:
+                sha:
+                  type: string
+                  description: The SHA hash of the head of the pull request.
     Error:
       type: object
       properties:
diff --git a/src/main/java/org/eclipsefoundation/git/eca/model/RevalidationResponse.java b/src/main/java/org/eclipsefoundation/git/eca/model/RevalidationResponse.java
new file mode 100644
index 00000000..9f04d7fe
--- /dev/null
+++ b/src/main/java/org/eclipsefoundation/git/eca/model/RevalidationResponse.java
@@ -0,0 +1,44 @@
+/*********************************************************************
+* Copyright (c) 2020 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.model;
+
+import java.net.URI;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
+import com.google.auto.value.AutoValue;
+
+/**
+ * Basic object representing a revalidation location post request. This was done to better integrate with the UI which
+ * fails on CORS requests when attempting to use natural redirects in AJAX.
+ * 
+ * @author Martin Lowe
+ *
+ */
+@AutoValue
+@JsonDeserialize(builder = AutoValue_RevalidationResponse.Builder.class)
+public abstract class RevalidationResponse {
+
+    public abstract URI getLocation();
+
+    public static Builder builder() {
+        return new AutoValue_RevalidationResponse.Builder();
+    }
+
+    @AutoValue.Builder
+    @JsonPOJOBuilder(withPrefix = "set")
+    public abstract static class Builder {
+        public abstract Builder setLocation(URI location);
+
+        public abstract RevalidationResponse build();
+    }
+}
\ No newline at end of file
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 fd87bdf7..088f3659 100644
--- a/src/main/java/org/eclipsefoundation/git/eca/resource/GithubWebhooksResource.java
+++ b/src/main/java/org/eclipsefoundation/git/eca/resource/GithubWebhooksResource.java
@@ -26,7 +26,6 @@ import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.Response;
-import javax.ws.rs.core.Response.Status;
 
 import org.eclipse.microprofile.config.inject.ConfigProperty;
 import org.eclipse.microprofile.rest.client.inject.RestClient;
@@ -43,6 +42,7 @@ import org.eclipsefoundation.git.eca.helper.CaptchaHelper;
 import org.eclipsefoundation.git.eca.helper.JwtHelper;
 import org.eclipsefoundation.git.eca.model.Commit;
 import org.eclipsefoundation.git.eca.model.GitUser;
+import org.eclipsefoundation.git.eca.model.RevalidationResponse;
 import org.eclipsefoundation.git.eca.model.ValidationRequest;
 import org.eclipsefoundation.git.eca.model.ValidationResponse;
 import org.eclipsefoundation.git.eca.namespace.GitEcaParameterNames;
@@ -170,8 +170,8 @@ public class GithubWebhooksResource {
         sb.append(tracking.getRepositoryFullName());
         sb.append("/pull/");
         sb.append(tracking.getPullRequestNumber());
-        // redirect to the pull request page on successful trigger of the webhook
-        return Response.status(Status.FOUND).location(URI.create(sb.toString())).build();
+        // respond with a URL to the new location in a standard request
+        return Response.ok(RevalidationResponse.builder().setLocation(URI.create(sb.toString())).build()).build();
     }
 
     /**
diff --git a/src/main/resources/templates/simple_fingerprint_ui.html b/src/main/resources/templates/simple_fingerprint_ui.html
index 6347fc72..69af38b8 100644
--- a/src/main/resources/templates/simple_fingerprint_ui.html
+++ b/src/main/resources/templates/simple_fingerprint_ui.html
@@ -266,14 +266,16 @@
         const $submitButton = $form.find('button');
         // disable the button so that requests won't be spammed
         $submitButton.attr("disabled", "disabled");
-        // use ajax to check the ECA status of the user
+        // use ajax to revalidate the commit with GH
         $.ajax({
           url: `/git/webhooks/github/revalidate/${$form.data('request-id')}`,
           data: $form.serialize(),
           type: 'POST',
-          success: function (data, status, xhr) {
+          success: function (data) {
             toast(`Revalidation complete! Forwarding to pull request.`, 'success');
-            window.location(xhr.getResponseHeader('Location'));
+            setTimeout(() => {
+              window.location.replace(data.location);
+            }, '2500');
           },
           error: function (xhr) {
             const json = JSON.parse(xhr.responseText);
-- 
GitLab


From f0f185f100b301c5ba808cdbf43dd5b8431075e2 Mon Sep 17 00:00:00 2001
From: Martin Lowe <martin.lowe@eclipse-foundation.org>
Date: Fri, 10 Mar 2023 10:55:55 -0500
Subject: [PATCH 3/3] Fix spec according to feedback

---
 spec/openapi.yaml | 27 +++++++++++----------------
 1 file changed, 11 insertions(+), 16 deletions(-)

diff --git a/spec/openapi.yaml b/spec/openapi.yaml
index 93e49e58..c1b7bcec 100644
--- a/spec/openapi.yaml
+++ b/spec/openapi.yaml
@@ -84,13 +84,6 @@ paths:
           description: Error while retrieving data
 
   /webhooks/github:
-    parameters:
-       - name: fingerprint
-         in: path
-         description: Unique ID for the request group
-         required: true
-         schema:
-            type: string
     post:
       tags:
         - Github validation processing
@@ -116,7 +109,7 @@ paths:
         content:
           application/json:
             schema:
-              $ref: "#/components/schemas/SystemHook"
+              $ref: "#/components/schemas/GithubWebhookEvent"
       responses:
         200:
           description: Success
@@ -135,17 +128,11 @@ paths:
         - Github validation processing
       summary: Gitlab webhook revalidation request
       description: Process incoming system hooks from GitLab
-      parameters:
-        - in: header
-          name: X-Gitlab-Event
-          schema: 
-            type: string
-          required: true
       requestBody:
         content:
-          application/json:
+          application/x-www-form-urlencoded:
             schema:
-              $ref: "#/components/schemas/SystemHook"
+              $ref: '#/components/schemas/RevalidationRequest'
       responses:
         200:
           description: Success
@@ -155,6 +142,8 @@ paths:
             application/json:
               schema:
                 $ref: "#/components/schemas/Error"
+        404:
+          description: Not found
   /webhooks/gitlab/system:
     post:
       tags:
@@ -541,6 +530,12 @@ components:
                 sha:
                   type: string
                   description: The SHA hash of the head of the pull request.
+    RevalidationRequest:
+      type: object
+      properties:
+        h-form-captcha-response:
+          type: string
+          description: the hCaptcha challenge response. 
     Error:
       type: object
       properties:
-- 
GitLab