Repository: openshift-pipelines/pipelines-as-code
Pull request #123 (2021-06-07 15:16:09)

Add support for Github Enteprise
Which basically goes down to be able to redefine the api_url.

No configuration needed everything boil down to be able to parse properly the
webhook which has the host information of where it's come from

Signed-off-by: Chmouel Boudjnah <chmouel@redhat.com>


codecov-commenter: # [Codecov](https://codecov.io/gh/openshift-pipelines/pipelines-as-code/pull/123?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) Report
> Merging [#123](https://codecov.io/gh/openshift-pipelines/pipelines-as-code/pull/123?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) (7310ad7) into [main](https://codecov.io/gh/openshift-pipelines/pipelines-as-code/commit/d2e50f3e3793bb03017883dae61c2e7eaf279aec?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) (d2e50f3) will **decrease** coverage by `0.07%`.
> The diff coverage is `53.84%`.

[![Impacted file tree graph](https://codecov.io/gh/openshift-pipelines/pipelines-as-code/pull/123/graphs/tree.svg?width=650&height=150&src=pr&token=XOBPWX11IU&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None)](https://codecov.io/gh/openshift-pipelines/pipelines-as-code/pull/123?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None)

```diff
@@            Coverage Diff             @@
##             main     #123      +/-   ##
==========================================
- Coverage   74.28%   74.20%   -0.08%     
==========================================
  Files          12       12              
  Lines         766      787      +21     
==========================================
+ Hits          569      584      +15     
- Misses        134      139       +5     
- Partials       63       64       +1     
```


| [Impacted Files](https://codecov.io/gh/openshift-pipelines/pipelines-as-code/pull/123?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None) | Coverage Δ | |
|---|---|---|
| [pkg/webvcs/github.go](https://codecov.io/gh/openshift-pipelines/pipelines-as-code/pull/123/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-cGtnL3dlYnZjcy9naXRodWIuZ28=) | `68.00% <50.00%> (-0.81%)` | :arrow_down: |
| [pkg/pipelineascode/acl.go](https://codecov.io/gh/openshift-pipelines/pipelines-as-code/pull/123/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-cGtnL3BpcGVsaW5lYXNjb2RlL2FjbC5nbw==) | `71.73% <60.00%> (-1.44%)` | :arrow_down: |
| [pkg/resolve/resolve.go](https://codecov.io/gh/openshift-pipelines/pipelines-as-code/pull/123/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None#diff-cGtnL3Jlc29sdmUvcmVzb2x2ZS5nbw==) | `91.54% <0.00%> (+1.22%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/openshift-pipelines/pipelines-as-code/pull/123?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/openshift-pipelines/pipelines-as-code/pull/123?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None). Last update [d2e50f3...7310ad7](https://codecov.io/gh/openshift-pipelines/pipelines-as-code/pull/123?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=None).


Patch:
diff --git a/config/401-trigger-issue-recheck.yaml b/config/401-trigger-issue-recheck.yaml
index 2dc3cba7..608b9579 100644
--- a/config/401-trigger-issue-recheck.yaml
+++ b/config/401-trigger-issue-recheck.yaml
@@ -19,6 +19,8 @@ spec:
       value: "issue-recheck"
     - name: event_type
       value: $(header.X-GitHub-Event)
+    - name: "ghe_host"
+      value: $(header.X-GitHub-Enterprise-Host)
     - name: owner
       value: $(body.repository.owner.login)
     - name: repository
@@ -57,6 +59,8 @@ spec:
     - name: sender
     - name: installation_id
     - name: trigger_target
+    - name: ghe_host
+      default: "api.github.com"
   resourcetemplates:
     - apiVersion: tekton.dev/v1beta1
       kind: PipelineRun
@@ -92,6 +96,8 @@ spec:
             value: $(tt.params.installation_id)
           - name: trigger_target
             value: $(tt.params.trigger_target)
+          - name: ghe_host
+            value: $(tt.params.ghe_host)
         pipelineSpec:
           params:
             - name: trigger_target
@@ -106,6 +112,7 @@ spec:
             - name: pull_request_number
             - name: sender
             - name: installation_id
+            - name: ghe_host
           workspaces:
             - name: secrets
           tasks:
@@ -113,6 +120,8 @@ spec:
               taskRef:
                 name: github-app-token
               params:
+                - name: github_api_url
+                  value: $(params.ghe_host)
                 - name: installation_id
                   value: $(params.installation_id)
               workspaces:
@@ -122,6 +131,8 @@ spec:
               runAfter: [get-token]
               taskSpec:
                 params:
+                  - name: ghe_host
+                    type: string
                   - name: action
                     type: string
                   - name: head_branch
@@ -181,9 +192,12 @@ spec:
                       EOF
                       cat /tmp/payload.json
                       pipelines-as-code --trigger-target=$(params.trigger_target) \
+                        --api-url="$(params.ghe_host)" \
                         --payload-file=/tmp/payload.json --token="$(params.token)" --webhook-type="$(params.event_type)"
 
               params:
+                - name: ghe_host
+                  value: $(params.ghe_host)
                 - name: action
                   value: "$(params.action)"
                 - name: head_branch
diff --git a/config/402-trigger-pull-request.yaml b/config/402-trigger-pull-request.yaml
index 464e8a6b..77b1c635 100644
--- a/config/402-trigger-pull-request.yaml
+++ b/config/402-trigger-pull-request.yaml
@@ -13,6 +13,8 @@ spec:
       value: "pull-request"
     - name: "event_type"
       value: $(header.X-GitHub-Event)
+    - name: "ghe_host"
+      value: $(header.X-GitHub-Enterprise-Host)
     - name: "owner"
       value: $(body.repository.owner.login)
     - name: "repository"
@@ -54,6 +56,8 @@ spec:
     - name: head_ref
     - name: installation_id
     - name: trigger_target
+    - name: ghe_host
+      default: "api.github.com"
   resourcetemplates:
     - apiVersion: tekton.dev/v1beta1
       kind: PipelineRun
@@ -65,6 +69,8 @@ spec:
       spec:
         serviceAccountName: pipelines-as-code-sa-el
         params:
+          - name: ghe_host
+            value: $(tt.params.ghe_host)
           - name: event_type
             value: $(tt.params.event_type)
           - name: trigger_target
@@ -89,6 +95,7 @@ spec:
             value: $(tt.params.installation_id)
         pipelineSpec:
           params:
+            - name: ghe_host
             - name: event_type
             - name: trigger_target
             - name: owner
@@ -107,6 +114,8 @@ spec:
               taskRef:
                 name: github-app-token
               params:
+                - name: github_api_url
+                  value: $(params.ghe_host)
                 - name: installation_id
                   value: $(params.installation_id)
               workspaces:
@@ -116,6 +125,8 @@ spec:
               runAfter: [get-token]
               taskSpec:
                 params:
+                  - name: ghe_host
+                    type: string
                   - name: trigger_target
                     type: string
                   - name: event_type
@@ -167,9 +178,14 @@ spec:
                           }
                       }
                       EOF
+                      cat /tmp/payload.json
                       pipelines-as-code --trigger-target=$(params.trigger_target) \
-                        --payload-file=/tmp/payload.json --token="$(params.token)" --webhook-type="$(params.event_type)"
+                        --api-url="$(params.ghe_host)" \
+                        --payload-file=/tmp/payload.json --token="$(params.token)" \
+                        --webhook-type="$(params.event_type)"
               params:
+                - name: ghe_host
+                  value: $(params.ghe_host)
                 - name: event_type
                   value: $(params.event_type)
                 - name: trigger_target
diff --git a/config/403-trigger-push.yaml b/config/403-trigger-push.yaml
index a99d5be7..68582b4f 100644
--- a/config/403-trigger-push.yaml
+++ b/config/403-trigger-push.yaml
@@ -11,6 +11,8 @@ spec:
   params:
     - name: "event_type"
       value: $(header.X-GitHub-Event)
+    - name: "ghe_host"
+      value: $(header.X-GitHub-Enterprise-Host)
     - name: "trigger_target"
       value: "push"
     - name: "owner"
@@ -44,6 +46,8 @@ metadata:
 spec:
   params:
     - name: event_type
+    - name: ghe_host
+      default: "api.github.com"
     - name: owner
     - name: repository
     - name: default_branch
@@ -65,6 +69,8 @@ spec:
       spec:
         serviceAccountName: pipelines-as-code-sa-el
         params:
+          - name: ghe_host
+            value: $(tt.params.ghe_host)
           - name: event_type
             value: $(tt.params.event_type)
           - name: trigger_target
@@ -89,6 +95,7 @@ spec:
             value: $(tt.params.installation_id)
         pipelineSpec:
           params:
+            - name: ghe_host
             - name: event_type
             - name: trigger_target
             - name: owner
@@ -107,6 +114,8 @@ spec:
               taskRef:
                 name: github-app-token
               params:
+                - name: github_api_url
+                  value: $(params.ghe_host)
                 - name: installation_id
                   value: $(params.installation_id)
               workspaces:
@@ -116,6 +125,8 @@ spec:
               runAfter: [get-token]
               taskSpec:
                 params:
+                  - name: ghe_host
+                    type: string
                   - name: trigger_target
                     type: string
                   - name: event_type
@@ -163,8 +174,11 @@ spec:
                       }
                       EOF
                       pipelines-as-code --trigger-target=$(params.trigger_target) \
+                        --api-url="$(params.ghe_host)" \
                         --payload-file=/tmp/payload.json --token="$(params.token)" --webhook-type="$(params.event_type)"
               params:
+                - name: ghe_host
+                  value: $(params.ghe_host)
                 - name: event_type
                   value: $(params.event_type)
                 - name: trigger_target
diff --git a/config/500-task-github-app-token.yaml b/config/500-task-github-app-token.yaml
index e8915242..6e53f2d4 100644
--- a/config/500-task-github-app-token.yaml
+++ b/config/500-task-github-app-token.yaml
@@ -35,7 +35,7 @@ spec:
     - name: application_id
       description: The application id for the GitHub application to request a token for.
       type: string
-      default: ""
+      default: "api.github.com"
 
     - name: private_key_path
       description: The key path inside the secret workspace
@@ -55,7 +55,7 @@ spec:
     - name: github_api_url
       description: GitHUB API URL endpoint
       type: string
-      default: "https://api.github.com"
+      default: "api.github.com"
 
   steps:
     - name: get-token
@@ -85,9 +85,9 @@ spec:
         from jwcrypto import jwk, jwt
 
         EXPIRE_MINUTES_AS_SECONDS = int(os.environ.get('GITHUBAPP_TOKEN_EXPIRATION_MINUTES', 10)) * 60
-        # TODO support github enteprise
-        GITHUB_API_URL = os.environ.get('GITHUB_API_URL')
-
+        GITHUB_API_URL = "https://" + os.environ.get('GITHUB_API_URL')
+        if GITHUB_API_URL != "https://api.github.com":
+          GITHUB_API_URL += "/api/v3"
 
         class GitHub():
             token = None
@@ -129,10 +129,12 @@ spec:
                         "Authorization": f"Bearer {app_token}",
                         "Accept": "application/vnd.github.machine-man-preview+json"
                     })
-
+                if not req.text.strip():
+                    raise Exception("Not getting a json: code: %s reason: %s" %
+                    (req.status_code, req.reason))
                 ret = req.json()
                 if 'token' not in ret:
-                    raise Exception(f"Authentication errors: {ret}")
+                    raise Exception(f"Authentication errors: {req.text}")
 
                 return ret['token']
 
diff --git a/hack/dev/gen-token.py b/hack/dev/gen-token.py
index e0f1cbad..d93c1dec 100755
--- a/hack/dev/gen-token.py
+++ b/hack/dev/gen-token.py
@@ -25,12 +25,14 @@ class GitHub():
                  private_key,
                  app_id,
                  expiration_time,
+                 github_api_url,
                  installation_id=None):
         if not isinstance(private_key, bytes):
             raise ValueError(f'"{private_key}" parameter must be byte-string')
         self._private_key = private_key
         self.app_id = app_id
         self.expiration_time = expiration_time
+        self.github_api_url = github_api_url
         self.token = self._get_token(installation_id)
 
     def _load_private_key(self, pem_key_bytes):
@@ -61,12 +63,15 @@ class GitHub():
             f"/app/installations/{installation_id}/access_tokens",
             headers={
                 "Authorization": f"Bearer {app_token}",
-                "Accept": "application/vnd.github.machine-man-preview+json"
+                "Accept": "application/json"
             })
 
+        if not req.text.strip():
+            raise Exception("Not getting a json: code: %s reason: %s" %
+                            (req.status_code, req.reason))
         ret = req.json()
         if 'token' not in ret:
-            raise Exception("Authentication errors")
+            raise Exception("Authentication errors: %s" % (req.text))
 
         return ret['token']
 
@@ -74,19 +79,18 @@ class GitHub():
         if self.token and 'Authorization' not in headers:
             headers.update({"Authorization": "Bearer " + self.token})
         if not url.startswith("http"):
-            url = f"{GITHUB_API_URL}{url}"
+            url = f"{self.github_api_url}{url}"
         return requests.request(method,
                                 url,
                                 headers=headers,
                                 data=json.dumps(data))
 
 
-def get_private_key():
-    secret = subprocess.run(
-        f"kubectl get secret {SECRET_NAME} -n{NAMESPACE} -o json",
-        shell=True,
-        check=True,
-        capture_output=True)
+def get_private_key(ns):
+    secret = subprocess.run(f"kubectl get secret {SECRET_NAME} -n{ns} -o json",
+                            shell=True,
+                            check=True,
+                            capture_output=True)
     jeez = json.loads(secret.stdout)
     return (base64.b64decode(jeez["data"]["application_id"]).decode(),
             base64.b64decode(jeez["data"]["private.key"]))
@@ -97,15 +101,16 @@ def main(args):
         mtime = os.path.getmtime(args.cache_file)
         if datetime.datetime.fromtimestamp(mtime) < datetime.datetime.now(
         ) - datetime.timedelta(seconds=args.token_expiration_time):
-            os.path.remove(args.cache_file)
+            os.remove(args.cache_file)
         else:
             print(open(args.cache_file).read())
             return
 
-    application_id, private_key = get_private_key()
+    application_id, private_key = get_private_key(args.install_namespace)
     github_app = GitHub(private_key,
                         application_id,
                         expiration_time=args.token_expiration_time,
+                        github_api_url=args.api_url,
                         installation_id=args.installation_id)
     print(github_app.token)
     if args.cache_file:
@@ -123,7 +128,17 @@ def parse_args():
                         type=int,
                         help="Installation_ID",
                         required=True)
+    parser.add_argument("-n",
+                        "--install-namespace",
+                        help="Install Namespace",
+                        default=os.environ.get("PAC_NAMESPACE", NAMESPACE))
+    parser.add_argument("-a",
+                        "--api-url",
+                        help="Github API URL",
+                        default=os.environ.get("GITHUB_API_URL",
+                                               GITHUB_API_URL))
     parser.add_argument(
+        "-c",
         "--cache-file",
         help=("Cache file will only regenerate after the expiration time,"
               " default: %d minutes") % (EXPIRE_MINUTES_AS_SECONDS / 60),
diff --git a/pkg/cli/interface.go b/pkg/cli/interface.go
index da79af34..feedd1cc 100644
--- a/pkg/cli/interface.go
+++ b/pkg/cli/interface.go
@@ -33,6 +33,9 @@ type Params interface {
 	// SetGitHubToken Set github token TODO: rename to a generic vcs
 	SetGitHubToken(string)
 
+	// SetGitAPIURL Set github token TODO: rename to a generic vcs
+	SetGitHubAPIURL(string)
+
 	Clients() (*Clients, error)
 	KubeClient() (k8s.Interface, error)
 }
diff --git a/pkg/cli/params.go b/pkg/cli/params.go
index c22e7652..127bb15f 100644
--- a/pkg/cli/params.go
+++ b/pkg/cli/params.go
@@ -19,6 +19,7 @@ type PacParams struct {
 	kubeContext    string
 	namespace      string
 	githubToken    string
+	githubAPIURL   string
 }
 
 var _ Params = (*PacParams)(nil)
@@ -31,6 +32,10 @@ func (p *PacParams) SetGitHubToken(token string) {
 	p.githubToken = token
 }
 
+func (p *PacParams) SetGitHubAPIURL(url string) {
+	p.githubAPIURL = url
+}
+
 // Set kube client based on config
 func (p *PacParams) kubeClient(config *rest.Config) (k8s.Interface, error) {
 	k8scs, err := k8s.NewForConfig(config)
@@ -92,7 +97,7 @@ func (p *PacParams) pacClient(config *rest.Config) (pacversioned.Interface, erro
 }
 
 func (p *PacParams) githubClient() webvcs.GithubVCS {
-	return webvcs.NewGithubVCS(p.githubToken)
+	return webvcs.NewGithubVCS(p.githubToken, p.githubAPIURL)
 }
 
 // KubeClient returns only the kube client, not the tekton client
diff --git a/pkg/flags/flags.go b/pkg/flags/flags.go
index 3b318fa5..3c4d5d02 100644
--- a/pkg/flags/flags.go
+++ b/pkg/flags/flags.go
@@ -10,11 +10,12 @@ import (
 const (
 	kubeConfig = "kubeconfig"
 	token      = "token"
+	apiURL     = "api-url"
 )
 
 // PacOptions holds struct of Pipeline as code Options
 type PacOptions struct {
-	KubeConfig, GithubToken string
+	KubeConfig, GithubToken, GithubAPIURL string
 }
 
 // InitParams initializes cli.Params based on flags defined in command
@@ -31,6 +32,12 @@ func InitParams(p cli.Params, cmd *cobra.Command) error {
 	}
 	p.SetGitHubToken(githubToken)
 
+	githubAPIURL, err := cmd.Flags().GetString(apiURL)
+	if err != nil {
+		return err
+	}
+	p.SetGitHubAPIURL(githubAPIURL)
+
 	// ensure that the config is valid by creating a client
 	if _, err := p.Clients(); err != nil {
 		return err
@@ -48,4 +55,8 @@ func AddPacOptions(cmd *cobra.Command) {
 	cmd.PersistentFlags().StringP(
 		token, "", os.Getenv("PAC_TOKEN"),
 		"Web VCS (ie: GitHub) Token")
+
+	cmd.PersistentFlags().StringP(
+		apiURL, "", os.Getenv("PAC_URL"),
+		"Web VCS (ie: GitHub Enteprise) API URL")
 }
diff --git a/pkg/generated/clientset/versioned/fake/register.go b/pkg/generated/clientset/versioned/fake/register.go
index 22138ab9..c39c6736 100644
--- a/pkg/generated/clientset/versioned/fake/register.go
+++ b/pkg/generated/clientset/versioned/fake/register.go
@@ -27,8 +27,10 @@ import (
 	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 )
 
-var scheme = runtime.NewScheme()
-var codecs = serializer.NewCodecFactory(scheme)
+var (
+	scheme = runtime.NewScheme()
+	codecs = serializer.NewCodecFactory(scheme)
+)
 
 var localSchemeBuilder = runtime.SchemeBuilder{
 	pipelinesascodev1alpha1.AddToScheme,
diff --git a/pkg/generated/clientset/versioned/scheme/register.go b/pkg/generated/clientset/versioned/scheme/register.go
index 35f02bf6..4af6054f 100644
--- a/pkg/generated/clientset/versioned/scheme/register.go
+++ b/pkg/generated/clientset/versioned/scheme/register.go
@@ -27,12 +27,14 @@ import (
 	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
 )
 
-var Scheme = runtime.NewScheme()
-var Codecs = serializer.NewCodecFactory(Scheme)
-var ParameterCodec = runtime.NewParameterCodec(Scheme)
-var localSchemeBuilder = runtime.SchemeBuilder{
-	pipelinesascodev1alpha1.AddToScheme,
-}
+var (
+	Scheme             = runtime.NewScheme()
+	Codecs             = serializer.NewCodecFactory(Scheme)
+	ParameterCodec     = runtime.NewParameterCodec(Scheme)
+	localSchemeBuilder = runtime.SchemeBuilder{
+		pipelinesascodev1alpha1.AddToScheme,
+	}
+)
 
 // AddToScheme adds all types of this clientset into the given scheme. This allows composition
 // of clientsets, like in:
diff --git a/pkg/generated/clientset/versioned/typed/pipelinesascode/v1alpha1/fake/fake_repository.go b/pkg/generated/clientset/versioned/typed/pipelinesascode/v1alpha1/fake/fake_repository.go
index ee4d6269..2408267b 100644
--- a/pkg/generated/clientset/versioned/typed/pipelinesascode/v1alpha1/fake/fake_repository.go
+++ b/pkg/generated/clientset/versioned/typed/pipelinesascode/v1alpha1/fake/fake_repository.go
@@ -77,7 +77,6 @@ func (c *FakeRepositories) List(ctx context.Context, opts v1.ListOptions) (resul
 func (c *FakeRepositories) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
 	return c.Fake.
 		InvokesWatch(testing.NewWatchAction(repositoriesResource, c.ns, opts))
-
 }
 
 // Create takes the representation of a repository and creates it.  Returns the server's representation of the repository, and an error, if there is any.
diff --git a/pkg/generated/informers/externalversions/generic.go b/pkg/generated/informers/externalversions/generic.go
index 7d80b5e3..96fbe707 100644
--- a/pkg/generated/informers/externalversions/generic.go
+++ b/pkg/generated/informers/externalversions/generic.go
@@ -55,7 +55,6 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource
 	// Group=pipelinesascode.tekton.dev, Version=v1alpha1
 	case v1alpha1.SchemeGroupVersion.WithResource("repositories"):
 		return &genericInformer{resource: resource.GroupResource(), informer: f.Pipelinesascode().V1alpha1().Repositories().Informer()}, nil
-
 	}
 
 	return nil, fmt.Errorf("no informer found for %v", resource)
diff --git a/pkg/pipelineascode/acl.go b/pkg/pipelineascode/acl.go
index 6934e18a..a328b6d3 100644
--- a/pkg/pipelineascode/acl.go
+++ b/pkg/pipelineascode/acl.go
@@ -30,7 +30,16 @@ func aclAllowedOkToTestFromAnOwner(ctx context.Context, cs *cli.Clients, runinfo
 	if rinfo.Event == nil {
 		return false, nil
 	}
-	rinfo.URL = rinfo.Event.(*github.IssueCommentEvent).Issue.GetPullRequestLinks().GetHTMLURL()
+
+	switch event := rinfo.Event.(type) {
+	case *github.IssueCommentEvent:
+		rinfo.URL = event.Issue.GetPullRequestLinks().GetHTMLURL()
+	case *github.PullRequestEvent:
+		rinfo.URL = event.GetPullRequest().GetHTMLURL()
+	default:
+		return false, nil
+	}
+
 	comments, err := cs.GithubClient.GetStringPullRequestComment(ctx, rinfo, okToTestCommentRegexp)
 	if err != nil {
 		return false, err
diff --git a/pkg/webvcs/github.go b/pkg/webvcs/github.go
index 3551280c..acc4c0e4 100644
--- a/pkg/webvcs/github.go
+++ b/pkg/webvcs/github.go
@@ -56,13 +56,23 @@ func (r *RunInfo) DeepCopyInto(out *RunInfo) {
 }
 
 // NewGithubVCS Create a new GitHub VCS object for token
-func NewGithubVCS(token string) GithubVCS {
+func NewGithubVCS(token string, apiURL string) GithubVCS {
 	ts := oauth2.StaticTokenSource(
 		&oauth2.Token{AccessToken: token},
 	)
 	tc := oauth2.NewClient(context.Background(), ts)
+
+	var client *github.Client
+	if apiURL != "" {
+		if !strings.HasPrefix(apiURL, "https") {
+			apiURL = "https://" + apiURL
+		}
+		client, _ = github.NewEnterpriseClient(apiURL, apiURL, tc)
+	} else {
+		client = github.NewClient(tc)
+	}
 	return GithubVCS{
-		Client: github.NewClient(tc),
+		Client: client,
 	}
 }
 
@@ -222,7 +232,6 @@ func (v GithubVCS) CheckSenderOrgMembership(ctx context.Context, runinfo *RunInf
 		&github.ListMembersOptions{
 			PublicOnly: true, // We can't list private member in a org
 		})
-
 	// If we are 404 it means we are checking a repo owner and not a org so let's bail out with grace
 	if resp != nil && resp.Response.StatusCode == http.StatusNotFound {
 		return false, nil


Test patch:
diff --git a/config/404-trigger-retest-comment.yaml b/config/404-trigger-retest-comment.yaml
index 4d8e4f1a..9314ae39 100644
--- a/config/404-trigger-retest-comment.yaml
+++ b/config/404-trigger-retest-comment.yaml
@@ -15,6 +15,8 @@ spec:
       value: $(body.action)
     - name: event_type
       value: $(header.X-GitHub-Event)
+    - name: "ghe_host"
+      value: $(header.X-GitHub-Enterprise-Host)
     - name: owner
       value: $(body.repository.owner.login)
     - name: sender
@@ -44,6 +46,8 @@ spec:
     - name: pull_request_url
     - name: installation_id
     - name: trigger_target
+    - name: ghe_host
+      default: "api.github.com"
   resourcetemplates:
     - apiVersion: tekton.dev/v1beta1
       kind: PipelineRun
@@ -59,6 +63,8 @@ spec:
             value: $(tt.params.action)
           - name: event_type
             value: $(tt.params.event_type)
+          - name: ghe_host
+            value: $(tt.params.ghe_host)
           - name: owner
             value: $(tt.params.owner)
           - name: sender
@@ -75,6 +81,7 @@ spec:
           params:
             - name: action
             - name: trigger_target
+            - name: ghe_host
             - name: event_type
             - name: owner
             - name: sender
@@ -88,6 +95,8 @@ spec:
               taskRef:
                 name: github-app-token
               params:
+                - name: github_api_url
+                  value: $(params.ghe_host)
                 - name: installation_id
                   value: $(params.installation_id)
               workspaces:
@@ -99,6 +108,8 @@ spec:
                 params:
                   - name: action
                     type: string
+                  - name: ghe_host
+                    type: string
                   - name: event_type
                     type: string
                   - name: owner
@@ -138,10 +149,13 @@ spec:
                       }
                       EOF
                       pipelines-as-code --trigger-target=$(params.trigger_target) \
+                        --api-url="$(params.ghe_host)" \
                         --payload-file=/tmp/payload.json --token="$(params.token)" --webhook-type="$(params.event_type)"
               params:
                 - name: action
                   value: "$(params.action)"
+                - name: ghe_host
+                  value: "$(params.ghe_host)"
                 - name: trigger_target
                   value: "$(params.trigger_target)"
                 - name: event_type
diff --git a/config/405-trigger-ok-to-test-comment.yaml b/config/405-trigger-ok-to-test-comment.yaml
index 5ff280a3..65bbe1a5 100644
--- a/config/405-trigger-ok-to-test-comment.yaml
+++ b/config/405-trigger-ok-to-test-comment.yaml
@@ -15,6 +15,8 @@ spec:
       value: "ok-to-test-comment"
     - name: event_type
       value: $(header.X-GitHub-Event)
+    - name: "ghe_host"
+      value: $(header.X-GitHub-Enterprise-Host)
     - name: owner
       value: $(body.repository.owner.login)
     - name: sender
diff --git a/pkg/pipelineascode/acl_test.go b/pkg/pipelineascode/acl_test.go
index 2a4c7fe9..61747ddc 100644
--- a/pkg/pipelineascode/acl_test.go
+++ b/pkg/pipelineascode/acl_test.go
@@ -25,8 +25,9 @@ func TestOkToTestComment(t *testing.T) {
 			name:          "good",
 			commentsReply: `[{"body": "/ok-to-test", "user": {"login": "owner"}}]`,
 			runinfo: &webvcs.RunInfo{
-				Owner:  "owner",
-				Sender: "nonowner",
+				Owner:     "owner",
+				Sender:    "nonowner",
+				EventType: "issue_comment",
 			},
 			allowed: true,
 			wantErr: false,
@@ -35,8 +36,9 @@ func TestOkToTestComment(t *testing.T) {
 			name:          "no-ok-to-test",
 			commentsReply: `[{"body": "Foo Bar", "user": {"login": "owner"}}]`,
 			runinfo: &webvcs.RunInfo{
-				Owner:  "owner",
-				Sender: "nonowner",
+				Owner:     "owner",
+				Sender:    "nonowner",
+				EventType: "issue_comment",
 			},
 			allowed: false,
 			wantErr: false,
@@ -45,8 +47,9 @@ func TestOkToTestComment(t *testing.T) {
 			name:          "ok-to-test-not-from-owner",
 			commentsReply: `[{"body": "/ok-to-test", "user": {"login": "notowner"}}]`,
 			runinfo: &webvcs.RunInfo{
-				Owner:  "owner",
-				Sender: "nonowner",
+				Owner:     "owner",
+				Sender:    "nonowner",
+				EventType: "issue_comment",
 			},
 			allowed: false,
 			wantErr: false,
diff --git a/pkg/test/params/params.go b/pkg/test/params/params.go
index 66d4e54e..586c6fb7 100644
--- a/pkg/test/params/params.go
+++ b/pkg/test/params/params.go
@@ -18,6 +18,10 @@ func (p FakeParams) SetKubeConfigPath(string) {
 func (p FakeParams) SetGitHubToken(string) {
 }
 
+// SetGitHubAPIURL Set github token TODO: rename to a generic vcs
+func (p FakeParams) SetGitHubAPIURL(string) {
+}
+
 func (p FakeParams) Clients() (*cli.Clients, error) {
 	return p.Fakeclients, nil
 }
diff --git a/pkg/webvcs/github_test.go b/pkg/webvcs/github_test.go
index 064a7fc2..5a602a2a 100644
--- a/pkg/webvcs/github_test.go
+++ b/pkg/webvcs/github_test.go
@@ -122,7 +122,7 @@ func TestPayLoadFix(t *testing.T) {
 	b, err := ioutil.ReadFile("testdata/pull_request_with_newlines.json")
 	assert.NilError(t, err)
 	ctx, _ := rtesting.SetupFakeContext(t)
-	gvcs := NewGithubVCS("none")
+	gvcs := NewGithubVCS("none", "")
 	logger, _ := getLogger()
 	_, err = gvcs.ParsePayload(ctx, logger, "pull_request", "pull_request", string(b))
 	// would bomb out on "assertion failed: error is not nil: invalid character
@@ -256,7 +256,7 @@ func TestParsePayload(t *testing.T) {
 	assert.NilError(t, err)
 
 	ctx, _ := rtesting.SetupFakeContext(t)
-	gvcs := NewGithubVCS("none")
+	gvcs := NewGithubVCS("none", "")
 	logger, _ := getLogger()
 
 	runinfo, err := gvcs.ParsePayload(ctx, logger, "pull_request", "pull_request", string(b))
@@ -270,7 +270,7 @@ func TestParsePayload(t *testing.T) {
 
 func TestParsePayloadInvalid(t *testing.T) {
 	ctx, _ := rtesting.SetupFakeContext(t)
-	gvcs := NewGithubVCS("none")
+	gvcs := NewGithubVCS("none", "")
 	logger, _ := getLogger()
 	_, err := gvcs.ParsePayload(ctx, logger, "pull_request", "pull_request", "hello moto")
 	assert.ErrorContains(t, err, "invalid character")
@@ -278,14 +278,14 @@ func TestParsePayloadInvalid(t *testing.T) {
 
 func TestParsePayloadUnkownEvent(t *testing.T) {
 	ctx, _ := rtesting.SetupFakeContext(t)
-	gvcs := NewGithubVCS("none")
+	gvcs := NewGithubVCS("none", "")
 	logger, _ := getLogger()
 	_, err := gvcs.ParsePayload(ctx, logger, "foo", "foo", "{\"hello\": \"moto\"}")
 	assert.ErrorContains(t, err, "unknown X-Github-Event")
 }
 
 func TestParsePayCannotParse(t *testing.T) {
-	gvcs := NewGithubVCS("none")
+	gvcs := NewGithubVCS("none", "")
 	ctx, _ := rtesting.SetupFakeContext(t)
 	logger, _ := getLogger()
 	_, err := gvcs.ParsePayload(ctx, logger, "gollum", "gollum", "{}")