Repository: openshift-pipelines/pipelines-as-code
Pull request #1982: fix: ignore bot users for blocking pull request when non authorized
Author: login: chmouel
Labels: name: bug
description: Something isn't working
Created: 2025-03-06T15:54:26Z | Merged: 2025-03-11T12:48:06Z



- Added logic to skip setting status for bot users in `CreateStatus` method.
- Updated `processEvent` to capture user type from GitHub events.
- Modified tests to include scenarios for bot users.
- Corrected minor formatting issues in documentation.

More details here: https://issues.redhat.com/browse/SRVKP-7242

# Changes <!-- 🎉🎉🎉 Thank you for the PR!!! 🎉🎉🎉 -->

<!-- Describe your changes here- ideally you can get that description straight from your descriptive commit message(s)! -->

# Submitter Checklist

- [x] 📝 Ensure your commit message is clear and informative. Refer to the How to write a git commit message guide. Include the commit message in the PR body rather than linking to an external site (e.g., Jira ticket).

- [x] ♽ Run make test lint before submitting a PR to avoid unnecessary CI processing. Consider installing [pre-commit](https://pre-commit.com/) and running pre-commit install in the repository root for an efficient workflow.

- [x] ✨ We use linters to maintain clean and consistent code. Run make lint before submitting a PR. Some linters offer a --fix mode, executable with make fix-linters (ensure [markdownlint](https://github.com/DavidAnson/markdownlint) and [golangci-lint](https://github.com/golangci/golangci-lint) are installed).

- [x] 📖 Document any user-facing features or changes in behavior.

- [x] 🧪 While 100% coverage isn't required, we encourage unit tests for code changes where possible.

- [ ] 🎁 If feasible, add an end-to-end test. See [README](https://github.com/openshift-pipelines/pipelines-as-code/blob/main/test/README.md) for details.

- [ ] 🔎 Address any CI test flakiness before merging, or provide a valid reason to bypass it (e.g., token rate limitations).

  (update the documentation accordingly)



Diff:
diff --git a/docs/content/docs/guide/running.md b/docs/content/docs/guide/running.md
index a2a8aaa60c..e02bf576d0 100644
--- a/docs/content/docs/guide/running.md
+++ b/docs/content/docs/guide/running.md
@@ -52,40 +52,47 @@ run a PipelineRun on CI:
   owns the repository.
 - The author of the pull request has permissions to push to branches inside the
   repository.
-
 - The author of the pull request is listed in the `OWNERS` file located in the main
   directory of the default branch on GitHub or your other service provider.
 (see below for the OWNERS file format).
 
-If the author of the pull request does not have the necessary permissions to run a
-PipelineRun, another user who does have the permissions can comment
-`/ok-to-test` on the pull request to trigger the PipelineRuns.
+If an unauthorized user attempts to trigger a PipelineRun through the creation
+of a Pull Request or by any other means, Pipelines-as-Code will block the
+execution and post a `'Pending'` status check. This check will inform the user
+that they lack the necessary permissions. Only authorized users can initiate the
+PipelineRun by commenting `/ok-to-test` on the pull request.
+
+GitHub bot users, identified through the GitHub API, are generally exempt from
+the `Pending` status check that would otherwise block a pull request. This
+means the status check is silently ignored for bots unless they have been
+explicitly authorized (using [OWNERS](#owners-file) file,
+[Policy]({{< relref "/docs/guide/policy" >}}) or other means).
 
 ## OWNERS file
 
 The `OWNERS` file follows a specific format similar to the Prow `OWNERS` file
 format (detailed at <https://www.kubernetes.dev/docs/guide/owners/>). We
 support a basic `OWNERS` configuration with `approvers` and `reviewers` lists,
-both of which have equal permissions for executing a `PipelineRun`.  
+both of which have equal permissions for executing a `PipelineRun`.
 
 If the `OWNERS` file uses `filters` instead of a simple configuration, we only
 consider the `.*` filter and extract the `approvers` and `reviewers` lists from
-it. Any other filters targeting specific files or directories are ignored.  
+it. Any other filters targeting specific files or directories are ignored.
 
 Additionally, `OWNERS_ALIASES` is supported and allows mapping alias names to
-lists of usernames.  
+lists of usernames.
 
 Including contributors in the `approvers` or `reviewers` lists within your
 `OWNERS` file grants them the ability to execute a `PipelineRun` via
-Pipelines-as-Code.  
+Pipelines-as-Code.
 
 For example, if your repository’s `main` or `master` branch contains the
-following `approvers` section:  
+following `approvers` section:
 
 ```yaml
 approvers:
   - approved
-```  
+```
 
 The user with the username `"approved"` will have the necessary
 permissions.
diff --git a/pkg/pipelineascode/match.go b/pkg/pipelineascode/match.go
index c6171bd9aa..e2a0263021 100644
--- a/pkg/pipelineascode/match.go
+++ b/pkg/pipelineascode/match.go
@@ -136,10 +136,11 @@ is that what you want? make sure you use -n when generating the secret, eg: echo
 	// trigger CI on the repository, as any user is able to comment on a pushed commit in open-source repositories.
 	if p.event.TriggerTarget == triggertype.Push && opscomments.IsAnyOpsEventType(p.event.EventType) {
 		status := provider.StatusOpts{
-			Status:     CompletedStatus,
-			Title:      "Permission denied",
-			Conclusion: failureConclusion,
-			DetailsURL: p.event.URL,
+			Status:       CompletedStatus,
+			Title:        "Permission denied",
+			Conclusion:   failureConclusion,
+			DetailsURL:   p.event.URL,
+			AccessDenied: true,
 		}
 		if allowed, err := p.checkAccessOrErrror(ctx, repo, status, "by GitOps comment on push commit"); !allowed {
 			return nil, err
@@ -151,10 +152,11 @@ is that what you want? make sure you use -n when generating the secret, eg: echo
 	// on comment we skip it for now, we are going to check later on
 	if p.event.TriggerTarget != triggertype.Push && p.event.EventType != opscomments.NoOpsCommentEventType.String() {
 		status := provider.StatusOpts{
-			Status:     queuedStatus,
-			Title:      "Pending approval, waiting for an /ok-to-test",
-			Conclusion: pendingConclusion,
-			DetailsURL: p.event.URL,
+			Status:       queuedStatus,
+			Title:        "Pending approval, waiting for an /ok-to-test",
+			Conclusion:   pendingConclusion,
+			DetailsURL:   p.event.URL,
+			AccessDenied: true,
 		}
 		if allowed, err := p.checkAccessOrErrror(ctx, repo, status, "via "+p.event.TriggerTarget.String()); !allowed {
 			return nil, err
@@ -266,10 +268,11 @@ func (p *PacRun) getPipelineRunsFromRepo(ctx context.Context, repo *v1alpha1.Rep
 	// we skipped previously so we can get the match from the event to the pipelineruns
 	if p.event.EventType == opscomments.NoOpsCommentEventType.String() || p.event.EventType == opscomments.OnCommentEventType.String() {
 		status := provider.StatusOpts{
-			Status:     queuedStatus,
-			Title:      "Pending approval, waiting for an /ok-to-test",
-			Conclusion: pendingConclusion,
-			DetailsURL: p.event.URL,
+			Status:       queuedStatus,
+			Title:        "Pending approval, waiting for an /ok-to-test",
+			Conclusion:   pendingConclusion,
+			DetailsURL:   p.event.URL,
+			AccessDenied: true,
 		}
 		if allowed, err := p.checkAccessOrErrror(ctx, repo, status, "by GitOps comment on push commit"); !allowed {
 			return nil, err
@@ -410,6 +413,7 @@ func (p *PacRun) checkAccessOrErrror(ctx context.Context, repo *v1alpha1.Reposit
 	}
 	p.eventEmitter.EmitMessage(repo, zap.InfoLevel, "RepositoryPermissionDenied", msg)
 	status.Text = msg
+
 	if err := p.vcx.CreateStatus(ctx, p.event, status); err != nil {
 		return false, fmt.Errorf("failed to run create status, user is not allowed to run the CI:: %w", err)
 	}
diff --git a/pkg/provider/github/github.go b/pkg/provider/github/github.go
index 8deaea9e35..d1946e0c55 100644
--- a/pkg/provider/github/github.go
+++ b/pkg/provider/github/github.go
@@ -52,6 +52,7 @@ type Provider struct {
 	repo          *v1alpha1.Repository
 	eventEmitter  *events.EventEmitter
 	PaginedNumber int
+	userType      string // The type of user i.e bot or not
 	skippedRun
 }
 
diff --git a/pkg/provider/github/parse_payload.go b/pkg/provider/github/parse_payload.go
index 12b846fe37..23a5ba0afe 100644
--- a/pkg/provider/github/parse_payload.go
+++ b/pkg/provider/github/parse_payload.go
@@ -276,6 +276,7 @@ func (v *Provider) processEvent(ctx context.Context, event *info.Event, eventInt
 		processedEvent.HeadBranch = processedEvent.BaseBranch // in push events Head Branch is the same as Basebranch
 		processedEvent.BaseURL = gitEvent.GetRepo().GetHTMLURL()
 		processedEvent.HeadURL = processedEvent.BaseURL // in push events Head URL is the same as BaseURL
+		v.userType = gitEvent.GetSender().GetType()
 	case *github.PullRequestEvent:
 		processedEvent.Repository = gitEvent.GetRepo().GetName()
 		if gitEvent.GetRepo() == nil {
@@ -291,6 +292,7 @@ func (v *Provider) processEvent(ctx context.Context, event *info.Event, eventInt
 		processedEvent.HeadURL = gitEvent.GetPullRequest().Head.GetRepo().GetHTMLURL()
 		processedEvent.Sender = gitEvent.GetPullRequest().GetUser().GetLogin()
 		processedEvent.EventType = event.EventType
+		v.userType = gitEvent.GetPullRequest().GetUser().GetType()
 
 		if gitEvent.Action != nil && provider.Valid(*gitEvent.Action, pullRequestLabelEvent) {
 			processedEvent.EventType = string(triggertype.LabelUpdate)
@@ -343,6 +345,7 @@ func (v *Provider) handleReRequestEvent(ctx context.Context, event *github.Check
 		// we allow the rerequest user here, not the push user, i guess it's
 		// fine because you can't do a rereq without being a github owner?
 		runevent.Sender = event.GetSender().GetLogin()
+		v.userType = event.GetSender().GetType()
 		return runevent, nil
 	}
 	runevent.PullRequestNumber = event.GetCheckRun().GetCheckSuite().PullRequests[0].GetNumber()
@@ -373,6 +376,7 @@ func (v *Provider) handleCheckSuites(ctx context.Context, event *github.CheckSui
 		// we allow the rerequest user here, not the push user, i guess it's
 		// fine because you can't do a rereq without being a github owner?
 		runevent.Sender = event.GetSender().GetLogin()
+		v.userType = event.GetSender().GetType()
 		return runevent, nil
 		// return nil, fmt.Errorf("check suite event is not supported for push events")
 	}
@@ -401,6 +405,7 @@ func (v *Provider) handleIssueCommentEvent(ctx context.Context, event *github.Is
 	if !event.GetIssue().IsPullRequest() {
 		return info.NewEvent(), fmt.Errorf("issue comment is not coming from a pull_request")
 	}
+	v.userType = event.GetSender().GetType()
 	opscomments.SetEventTypeAndTargetPR(runevent, event.GetComment().GetBody())
 	// We are getting the full URL so we have to get the last part to get the PR number,
 	// we don't have to care about URL query string/hash and other stuff because
@@ -424,6 +429,7 @@ func (v *Provider) handleCommitCommentEvent(ctx context.Context, event *github.C
 	runevent.Organization = event.GetRepo().GetOwner().GetLogin()
 	runevent.Repository = event.GetRepo().GetName()
 	runevent.Sender = event.GetSender().GetLogin()
+	v.userType = event.GetSender().GetType()
 	runevent.URL = event.GetRepo().GetHTMLURL()
 	runevent.SHA = event.GetComment().GetCommitID()
 	runevent.HeadURL = runevent.URL
diff --git a/pkg/provider/github/status.go b/pkg/provider/github/status.go
index 4723ec3f70..05aa2d2412 100644
--- a/pkg/provider/github/status.go
+++ b/pkg/provider/github/status.go
@@ -20,6 +20,11 @@ import (
 	tektonv1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
 )
 
+const (
+	botType         = "Bot"
+	pendingApproval = "Pending approval, waiting for an /ok-to-test"
+)
+
 const taskStatusTemplate = `
 <table>
   <tr><th>Status</th><th>Duration</th><th>Name</th></tr>
@@ -35,8 +40,6 @@ const taskStatusTemplate = `
 {{- end }}
 </table>`
 
-const pendingApproval = "Pending approval, waiting for an /ok-to-test"
-
 func (v *Provider) getExistingCheckRunID(ctx context.Context, runevent *info.Event, status provider.StatusOpts) (*int64, error) {
 	opt := github.ListOptions{PerPage: v.PaginedNumber}
 	for {
@@ -350,6 +353,11 @@ func (v *Provider) CreateStatus(ctx context.Context, runevent *info.Event, statu
 		return fmt.Errorf("cannot set status on github no token or url set")
 	}
 
+	// If the request comes from a bot user, skip setting the status and just log the event silently
+	if statusOpts.AccessDenied && v.userType == botType {
+		return nil
+	}
+
 	switch statusOpts.Conclusion {
 	case "success":
 		statusOpts.Title = "Success"
@@ -386,7 +394,6 @@ func (v *Provider) CreateStatus(ctx context.Context, runevent *info.Event, statu
 		onPr = "/" + statusOpts.OriginalPipelineRunName
 	}
 	statusOpts.Summary = fmt.Sprintf("%s%s %s", v.pacInfo.ApplicationName, onPr, statusOpts.Summary)
-
 	// If we have an installationID which mean we have a github apps and we can use the checkRun API
 	if runevent.InstallationID > 0 {
 		return v.getOrUpdateCheckRunStatus(ctx, runevent, statusOpts)
diff --git a/pkg/provider/github/status_test.go b/pkg/provider/github/status_test.go
index d76b311047..d0b51d374a 100644
--- a/pkg/provider/github/status_test.go
+++ b/pkg/provider/github/status_test.go
@@ -248,6 +248,8 @@ func TestGithubProviderCreateStatus(t *testing.T) {
 		titleSubstr        string
 		nilCompletedAtDate bool
 		githubApps         bool
+		accessDenied       bool
+		isBot              bool
 	}
 	tests := []struct {
 		name                 string
@@ -334,6 +336,36 @@ func TestGithubProviderCreateStatus(t *testing.T) {
 			want:    &github.CheckRun{ID: &resultid},
 			wantErr: false,
 		},
+		{
+			name: "failure from bot",
+			args: args{
+				runevent:     runEvent,
+				status:       "completed",
+				conclusion:   "failure",
+				text:         "Nay",
+				detailsURL:   "https://cireport.com",
+				titleSubstr:  "Failed",
+				githubApps:   true,
+				accessDenied: true,
+				isBot:        true,
+			},
+			wantErr: false,
+		},
+		{
+			name: "success from bot",
+			args: args{
+				runevent:    runEvent,
+				status:      "completed",
+				conclusion:  "failure",
+				text:        "Nay",
+				detailsURL:  "https://cireport.com",
+				titleSubstr: "Failed",
+				githubApps:  true,
+				isBot:       true,
+			},
+			wantErr: false,
+			want:    &github.CheckRun{ID: &resultid},
+		},
 		{
 			name: "skipped",
 			args: args{
@@ -378,14 +410,18 @@ func TestGithubProviderCreateStatus(t *testing.T) {
 			gcvs.Client = fakeclient
 			gcvs.Logger, _ = logger.GetLogger()
 			gcvs.Run = params.New()
+			if tt.args.isBot {
+				gcvs.userType = "Bot"
+			}
 
+			checkRunCreated := false
 			mux.HandleFunc("/repos/check/run/statuses/sha", func(_ http.ResponseWriter, _ *http.Request) {})
 			mux.HandleFunc(fmt.Sprintf("/repos/check/run/check-runs/%d", checkrunid), func(rw http.ResponseWriter, r *http.Request) {
 				bit, _ := io.ReadAll(r.Body)
 				checkRun := &github.CheckRun{}
 				err := json.Unmarshal(bit, checkRun)
 				assert.NilError(t, err)
-
+				checkRunCreated = true
 				if tt.args.nilCompletedAtDate {
 					// I guess that's the way you check for an undefined year,
 					// or maybe i don't understand fully how go works😅
@@ -402,6 +438,7 @@ func TestGithubProviderCreateStatus(t *testing.T) {
 				_, err = fmt.Fprintf(rw, `{"id": %d}`, resultid)
 				assert.NilError(t, err)
 			})
+
 			if tt.addExistingCheckruns {
 				tt.args.runevent.SHA = "sha"
 				mux.HandleFunc(fmt.Sprintf("/repos/%v/%v/commits/%v/check-runs", tt.args.runevent.Organization, tt.args.runevent.Repository, tt.args.runevent.SHA), func(w http.ResponseWriter, _ *http.Request) {
@@ -430,6 +467,7 @@ func TestGithubProviderCreateStatus(t *testing.T) {
 				Conclusion:      tt.args.conclusion,
 				Text:            tt.args.text,
 				DetailsURL:      tt.args.detailsURL,
+				AccessDenied:    tt.args.accessDenied,
 			}
 			if tt.pr != nil {
 				status.PipelineRun = tt.pr
@@ -469,6 +507,14 @@ func TestGithubProviderCreateStatus(t *testing.T) {
 				t.Errorf("GithubProvider.CreateStatus() error = %v, wantErr %v", err, tt.wantErr)
 				return
 			}
+			if tt.want == nil && checkRunCreated {
+				t.Errorf("Check run should have not be created for this test")
+				return
+			}
+			if tt.want != nil && !checkRunCreated {
+				t.Errorf("Check run should have been created for this test")
+				return
+			}
 		})
 	}
 }
diff --git a/pkg/provider/interface.go b/pkg/provider/interface.go
index 528081f576..fdfabd08b0 100644
--- a/pkg/provider/interface.go
+++ b/pkg/provider/interface.go
@@ -24,6 +24,7 @@ type StatusOpts struct {
 	Summary                  string
 	Title                    string
 	InstanceCountForCheckRun int
+	AccessDenied             bool
 }
 
 type Interface interface {


Reviews:
user: login: copilot-pull-request-reviewer[bot]
body: ## PR Overview

This PR implements a workaround to ignore bot users (usernames ending in "[bot]") to prevent conflicts between PaC and prow during GitOps commands.  
- Added a CheckBot function with a corresponding regex-based rule and unit tests in pkg/acl.  
- Updated the docs to explain how bot users are handled.  
- Modified the access check in Pipelines-as-Code to silently ignore bot users when determining permissions.

### Reviewed Changes

| File                                 | Description                                                             |
| ------------------------------------ | ----------------------------------------------------------------------- |
| pkg/acl/robots.go                    | Introduced a CheckBot function with regex-based bot detection.          |
| pkg/acl/robots_test.go               | Added unit tests for various sender names to validate bot detection.    |
| docs/content/docs/guide/running.md     | Updated the documentation to describe bot exemptions in PipelineRun.    |
| pkg/pipelineascode/match.go          | Added a conditional check to bypass status creation for bot users.      |

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.



state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-06T15:55:02Z
user: login: chmouel
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-06T15:57:00Z
user: login: zakisk
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-06T17:49:54Z
user: login: zakisk
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-07T07:15:02Z
user: login: chmouel
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-07T08:29:16Z
user: login: zakisk
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-07T08:48:30Z
user: login: chmouel
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-07T09:16:14Z
user: login: zakisk
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-07T09:21:04Z
user: login: chmouel
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-07T10:26:51Z
user: login: chmouel
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-07T10:27:20Z
user: login: copilot-pull-request-reviewer[bot]
body: ## PR Overview

This PR introduces logic to ignore status updates for GitHub bot users, updates documentation to explain the behavior, and expands test coverage for bot scenarios. Key changes include updates in status creation logic to bypass bot requests, adjustments to event payload parsing to capture the user type, and modifications to tests to verify the new behavior.

### Reviewed Changes

| File                                     | Description                                             |
| ---------------------------------------- | ------------------------------------------------------- |
| docs/content/docs/guide/running.md       | Updated documentation to describe bot exemption behavior|
| pkg/provider/github/status.go             | Added condition to skip setting status for bot users    |
| pkg/provider/github/status_test.go        | Extended tests to include bot user scenarios            |
| pkg/provider/github/github.go             | Added a new field for user type                         |
| pkg/pipelineascode/match.go                | Marked statuses with AccessDenied for unauthorized users|
| pkg/provider/interface.go                  | Added AccessDenied field to StatusOpts                  |
| pkg/provider/github/parse_payload.go       | Updated payload parsing to capture sender user type     |

Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.

<details>
<summary>Comments suppressed due to low confidence (1)</summary>

**pkg/provider/github/status.go:350**
* [nitpick] Consider improving the error message for clarity, e.g. 'cannot set status on GitHub: no token or URL provided'.
```
return fmt.Errorf("cannot set status on github no token or url set")
```
</details>


state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-07T10:49:51Z
user: login: zakisk
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-10T12:57:47Z
user: login: zakisk
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-10T12:59:29Z
user: login: zakisk
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-10T13:03:37Z
user: login: chmouel
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-11T10:18:23Z
user: login: chmouel
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-11T10:18:41Z
user: login: chmouel
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-11T10:25:38Z
user: login: pipelines-as-code[bot]
body: 
Congrats @chmouel your PR Has been approved 🎉

### ✅ Pull Request Approved

*Approval Status:* 
* Required Approvals: 1
* Current Approvals: 1

### 👥 Reviewers Who Approved:
| Reviewer | Permission Level | Approval Status |
|----------|------------------|----------------|
| @zakisk | `admin` | ✅ |


### 📝 Next Steps
* Ensure all required checks pass
* Comply with branch protection rules
* Request a maintainer to merge using the `/merge` command (or merge it
directly if you have repository permission).


*Automated by the [PAC Boussole](https://github.com/openshift-pipelines/pac-boussole) 🧭* 


state: APPROVED
author_association: NONE
submitted_at: 2025-03-11T10:53:58Z

Review comments:
diff_hunk: @@ -410,6 +411,12 @@ func (p *PacRun) checkAccessOrErrror(ctx context.Context, repo *v1alpha1.Reposit
 	}
 	p.eventEmitter.EmitMessage(repo, zap.InfoLevel, "RepositoryPermissionDenied", msg)
 	status.Text = msg
+
+	// don't create a status if the user is a bot, just silently don't allow it to run CI
+	if acl.CheckBot(p.event.Sender) {
+		return false, nil
+	}
+
path: pkg/pipelineascode/match.go
user: login: Copilot
body: Consider moving the bot check earlier in the function—before emitting the 'RepositoryPermissionDenied' message—to avoid logging a failure message for bot users even though their status is silently ignored.
```suggestion

```
created_at: 2025-03-06T15:55:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -410,6 +411,12 @@ func (p *PacRun) checkAccessOrErrror(ctx context.Context, repo *v1alpha1.Reposit
 	}
 	p.eventEmitter.EmitMessage(repo, zap.InfoLevel, "RepositoryPermissionDenied", msg)
 	status.Text = msg
+
+	// don't create a status if the user is a bot, just silently don't allow it to run CI
+	if acl.CheckBot(p.event.Sender) {
+		return false, nil
+	}
+
path: pkg/pipelineascode/match.go
user: login: chmouel
body: Thanks buddy for checkin gthis but we actually do want that error message in the log.... we only do this to not set the status
created_at: 2025-03-06T15:56:59Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,16 @@
+package acl
+
+import "regexp"
+
+var BotNames = []string{
+	`.*\[bot\]$`, // Github
+}
+
+func CheckBot(sender string) bool {
+	for _, botName := range BotNames {
+		if regexp.MustCompile(botName).MatchString(sender) {
+			return true
+		}
+	}
+	return false
+}
path: pkg/acl/robots.go
user: login: zakisk
body: @chmouel in GitHub's [Get User API](https://docs.github.com/en/rest/users/users?apiVersion=2022-11-28#get-a-user) endpoint, there is field [type](https://github.com/google/go-github/blob/56f5036c4e778d1b3f84ff4eff716fd3c652f342/github/users.go#L42) which indicates that the user is a human or bot. if sender is a real user then type's value will be `User` or if its a bot then it will be `Bot`. (you can curl it) and this seems more safer way to me.
created_at: 2025-03-06T17:49:54Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,16 @@
+package acl
+
+import "regexp"
+
+var BotNames = []string{
+	`.*\[bot\]$`, // Github
+}
+
+func CheckBot(sender string) bool {
+	for _, botName := range BotNames {
+		if regexp.MustCompile(botName).MatchString(sender) {
+			return true
+		}
+	}
+	return false
+}
path: pkg/acl/robots.go
user: login: zakisk
body: @chmouel or more convenient way I can see is, in [IssueCommentEvent in ParsePayload](https://github.com/openshift-pipelines/pipelines-as-code/blob/504f3caee397f00cbccc699fed0e96933d00fa96/pkg/provider/github/parse_payload.go#L236) you have [User (Sender)](https://github.com/google/go-github/blob/56f5036c4e778d1b3f84ff4eff716fd3c652f342/github/event_types.go#L707) struct in IssueCommentEvent struct, you can add a new field in [Event](https://github.com/openshift-pipelines/pipelines-as-code/blob/504f3caee397f00cbccc699fed0e96933d00fa96/pkg/params/info/events.go#L9) called UserType and in ParsePayload assign the value of IssueCommentEvent.Sender.Type to it and then checking it in checkAccessOrError to decide whether create a check-run or not.
created_at: 2025-03-07T07:15:02Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,16 @@
+package acl
+
+import "regexp"
+
+var BotNames = []string{
+	`.*\[bot\]$`, // Github
+}
+
+func CheckBot(sender string) bool {
+	for _, botName := range BotNames {
+		if regexp.MustCompile(botName).MatchString(sender) {
+			return true
+		}
+	}
+	return false
+}
path: pkg/acl/robots.go
user: login: chmouel
body: that's a good idea but i don't think that's on comment we need to set this but on CreateStatus, will rework this appropriately 
created_at: 2025-03-07T08:29:16Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,16 @@
+package acl
+
+import "regexp"
+
+var BotNames = []string{
+	`.*\[bot\]$`, // Github
+}
+
+func CheckBot(sender string) bool {
+	for _, botName := range BotNames {
+		if regexp.MustCompile(botName).MatchString(sender) {
+			return true
+		}
+	}
+	return false
+}
path: pkg/acl/robots.go
user: login: zakisk
body: Yeah, my take was, if we already have info from GitHub about whether user is bot or not we can set that in event and we have event object access in checkAccessOrError func instead of comparing regex.
created_at: 2025-03-07T08:48:30Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,16 @@
+package acl
+
+import "regexp"
+
+var BotNames = []string{
+	`.*\[bot\]$`, // Github
+}
+
+func CheckBot(sender string) bool {
+	for _, botName := range BotNames {
+		if regexp.MustCompile(botName).MatchString(sender) {
+			return true
+		}
+	}
+	return false
+}
path: pkg/acl/robots.go
user: login: chmouel
body: yeah that i agree altho i don't think other providers would have that kind of things, we'll keep it for github for now
created_at: 2025-03-07T09:16:14Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,16 @@
+package acl
+
+import "regexp"
+
+var BotNames = []string{
+	`.*\[bot\]$`, // Github
+}
+
+func CheckBot(sender string) bool {
+	for _, botName := range BotNames {
+		if regexp.MustCompile(botName).MatchString(sender) {
+			return true
+		}
+	}
+	return false
+}
path: pkg/acl/robots.go
user: login: zakisk
body: When openshift-ci is commenting that time this pending check is being created, I guess 🤔 , right?
created_at: 2025-03-07T09:21:04Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,16 @@
+package acl
+
+import "regexp"
+
+var BotNames = []string{
+	`.*\[bot\]$`, // Github
+}
+
+func CheckBot(sender string) bool {
+	for _, botName := range BotNames {
+		if regexp.MustCompile(botName).MatchString(sender) {
+			return true
+		}
+	}
+	return false
+}
path: pkg/acl/robots.go
user: login: chmouel
body: yeah... it's a prow vs pac thing, openshift-ci post a comment with /retest and that is blocking the pipeline then
created_at: 2025-03-07T10:26:51Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,16 @@
+package acl
+
+import "regexp"
+
+var BotNames = []string{
+	`.*\[bot\]$`, // Github
+}
+
+func CheckBot(sender string) bool {
+	for _, botName := range BotNames {
+		if regexp.MustCompile(botName).MatchString(sender) {
+			return true
+		}
+	}
+	return false
+}
path: pkg/acl/robots.go
user: login: chmouel
body: I have updated the PR with the right field, it was a bit more complicated since we want to bypass only for the access denied and pending creation, PTAL
created_at: 2025-03-07T10:27:20Z
author_association: MEMBER
diff_hunk: @@ -52,40 +52,46 @@ run a PipelineRun on CI:
   owns the repository.
 - The author of the pull request has permissions to push to branches inside the
   repository.
-
 - The author of the pull request is listed in the `OWNERS` file located in the main
   directory of the default branch on GitHub or your other service provider.
 (see below for the OWNERS file format).
 
-If the pull request author does not have the necessary permissions to run a
-PipelineRun, another user who does have the necessary permissions can comment
-`/ok-to-test` on the pull request to run the PipelineRun.
+If an unauthorized user attempts to trigger a PipelineRun through the creation
+of a Pull Request or by any other means, Pipelines-as-Code will block the
+execution and post a `'Failed'` status check. This check will inform the user
+that they lack the necessary permissions. Only authorized users can initiate the
+PipelineRun by commenting `/ok-to-test` on the pull request.
+
+GitHub bot users, identified through the GitHub API, are generally exempt from
+the `'Failed'` status check that would otherwise block a pull request. This
+means the status check is silently ignored for bots unless they have been
+explicitly authorized to be subject to the check.
path: docs/content/docs/guide/running.md
user: login: zakisk
body: > unless they have been explicitly authorized to be subject to the check

@chmouel do you mean OWNERS file here?
created_at: 2025-03-10T12:57:47Z
author_association: MEMBER
diff_hunk: @@ -52,40 +52,46 @@ run a PipelineRun on CI:
   owns the repository.
 - The author of the pull request has permissions to push to branches inside the
   repository.
-
 - The author of the pull request is listed in the `OWNERS` file located in the main
   directory of the default branch on GitHub or your other service provider.
 (see below for the OWNERS file format).
 
-If the pull request author does not have the necessary permissions to run a
-PipelineRun, another user who does have the necessary permissions can comment
-`/ok-to-test` on the pull request to run the PipelineRun.
+If an unauthorized user attempts to trigger a PipelineRun through the creation
+of a Pull Request or by any other means, Pipelines-as-Code will block the
+execution and post a `'Failed'` status check. This check will inform the user
path: docs/content/docs/guide/running.md
user: login: zakisk
body: @chmouel but in code, we create ""queued" status rather than "failed" on pull request, I think this needs rephrasing 🤔 
created_at: 2025-03-10T12:59:28Z
author_association: MEMBER
diff_hunk: @@ -52,40 +52,46 @@ run a PipelineRun on CI:
   owns the repository.
 - The author of the pull request has permissions to push to branches inside the
   repository.
-
 - The author of the pull request is listed in the `OWNERS` file located in the main
   directory of the default branch on GitHub or your other service provider.
 (see below for the OWNERS file format).
 
-If the pull request author does not have the necessary permissions to run a
-PipelineRun, another user who does have the necessary permissions can comment
-`/ok-to-test` on the pull request to run the PipelineRun.
+If an unauthorized user attempts to trigger a PipelineRun through the creation
+of a Pull Request or by any other means, Pipelines-as-Code will block the
+execution and post a `'Failed'` status check. This check will inform the user
+that they lack the necessary permissions. Only authorized users can initiate the
+PipelineRun by commenting `/ok-to-test` on the pull request.
+
+GitHub bot users, identified through the GitHub API, are generally exempt from
+the `'Failed'` status check that would otherwise block a pull request. This
path: docs/content/docs/guide/running.md
user: login: zakisk
body: ```suggestion
Verification of bot users is currently only supported on GitHub. These bot users, identified through the GitHub API, are generally exempt from the 'Failed' status check that would otherwise block a pull request. This
```
created_at: 2025-03-10T13:03:37Z
author_association: MEMBER
diff_hunk: @@ -52,40 +52,46 @@ run a PipelineRun on CI:
   owns the repository.
 - The author of the pull request has permissions to push to branches inside the
   repository.
-
 - The author of the pull request is listed in the `OWNERS` file located in the main
   directory of the default branch on GitHub or your other service provider.
 (see below for the OWNERS file format).
 
-If the pull request author does not have the necessary permissions to run a
-PipelineRun, another user who does have the necessary permissions can comment
-`/ok-to-test` on the pull request to run the PipelineRun.
+If an unauthorized user attempts to trigger a PipelineRun through the creation
+of a Pull Request or by any other means, Pipelines-as-Code will block the
+execution and post a `'Failed'` status check. This check will inform the user
+that they lack the necessary permissions. Only authorized users can initiate the
+PipelineRun by commenting `/ok-to-test` on the pull request.
+
+GitHub bot users, identified through the GitHub API, are generally exempt from
+the `'Failed'` status check that would otherwise block a pull request. This
path: docs/content/docs/guide/running.md
user: login: chmouel
body: I don't think we need to add this, it's already about Github bots and not others...
created_at: 2025-03-11T10:18:22Z
author_association: MEMBER
diff_hunk: @@ -52,40 +52,46 @@ run a PipelineRun on CI:
   owns the repository.
 - The author of the pull request has permissions to push to branches inside the
   repository.
-
 - The author of the pull request is listed in the `OWNERS` file located in the main
   directory of the default branch on GitHub or your other service provider.
 (see below for the OWNERS file format).
 
-If the pull request author does not have the necessary permissions to run a
-PipelineRun, another user who does have the necessary permissions can comment
-`/ok-to-test` on the pull request to run the PipelineRun.
+If an unauthorized user attempts to trigger a PipelineRun through the creation
+of a Pull Request or by any other means, Pipelines-as-Code will block the
+execution and post a `'Failed'` status check. This check will inform the user
path: docs/content/docs/guide/running.md
user: login: chmouel
body: yes good point
created_at: 2025-03-11T10:18:41Z
author_association: MEMBER
diff_hunk: @@ -52,40 +52,46 @@ run a PipelineRun on CI:
   owns the repository.
 - The author of the pull request has permissions to push to branches inside the
   repository.
-
 - The author of the pull request is listed in the `OWNERS` file located in the main
   directory of the default branch on GitHub or your other service provider.
 (see below for the OWNERS file format).
 
-If the pull request author does not have the necessary permissions to run a
-PipelineRun, another user who does have the necessary permissions can comment
-`/ok-to-test` on the pull request to run the PipelineRun.
+If an unauthorized user attempts to trigger a PipelineRun through the creation
+of a Pull Request or by any other means, Pipelines-as-Code will block the
+execution and post a `'Failed'` status check. This check will inform the user
+that they lack the necessary permissions. Only authorized users can initiate the
+PipelineRun by commenting `/ok-to-test` on the pull request.
+
+GitHub bot users, identified through the GitHub API, are generally exempt from
+the `'Failed'` status check that would otherwise block a pull request. This
+means the status check is silently ignored for bots unless they have been
+explicitly authorized to be subject to the check.
path: docs/content/docs/guide/running.md
user: login: chmouel
body: owners file or other means, will add some
created_at: 2025-03-11T10:25:38Z
author_association: MEMBER

PR comments:
user: login: chmouel
created_at: 2025-03-07T09:25:45Z
body: /label bug
author_association: MEMBER
user: login: pipelines-as-code[bot]
created_at: 2025-03-07T09:26:15Z
body: ✅ Added labels: <b>bug</b>.
author_association: NONE
user: login: chmouel
created_at: 2025-03-07T09:28:12Z
body: used the boussole to generate and then grabe the payload and make sure the type is Bot for a bot 
![image](https://github.com/user-attachments/assets/50755fe2-d959-4a83-9222-661b28632dac)


author_association: MEMBER
user: login: arewm
created_at: 2025-03-07T20:20:09Z
body: Is it possible to spoof the `bot` metadata? Is this only supported for PAC functionality for GitHub or would it also support actions for other source control platforms?
author_association: NONE
user: login: chmouel
created_at: 2025-03-10T08:03:53Z
body: @arewm that is not possible, if malicious user was able to spoof the github payload then it would be a severe security issue.

We enforce using webhook payload secret for that reason...
author_association: MEMBER
user: login: zakisk
created_at: 2025-03-11T07:15:19Z
body: /test
author_association: MEMBER
user: login: zakisk
created_at: 2025-03-11T07:43:19Z
body: > Matched the following files: [/workspace/source/docs/themes/hugo-book/go.mod /workspace/source/go.mod /workspace/source/go.sum]
Upload /workspace/source/go-build-cache content to oci image image-registry.openshift-image-registry.svc:5000/pipelines-as-code-ci/cache-go:238b6c9bda4a3abc4aedfc9e6e6fdb170352ef684fcf910977f45b651abe628e
Error: GET https://image-registry.openshift-image-registry.svc:5000/openshift/token?scope=repository%3Apipelines-as-code-ci%2Fcache-go%3Apush%2Cpull&service=: unexpected status code 401 Unauthorized

still failing 🤔 
author_association: MEMBER
user: login: chmouel
created_at: 2025-03-11T09:01:22Z
body: /retest
author_association: MEMBER
user: login: chmouel
created_at: 2025-03-11T09:11:02Z
body: It fails on the first time as always.... 
author_association: MEMBER
user: login: zakisk
created_at: 2025-03-11T09:13:34Z
body: @chmouel can you please see my comments, otherwise nothing is left that stopping merge.
author_association: MEMBER
user: login: chmouel
created_at: 2025-03-11T10:41:14Z
body: lmk wdyt @zakisk 
author_association: MEMBER
user: login: zakisk
created_at: 2025-03-11T10:53:46Z
body: /lgtm
author_association: MEMBER
user: login: zakisk
created_at: 2025-03-11T12:47:55Z
body: /merge
author_association: MEMBER
user: login: pipelines-as-code[bot]
created_at: 2025-03-11T12:48:07Z
body: 
### ✅ PR Successfully Merged

* Merge method: `rebase`
* Merged by: **@zakisk**
* Total approvals: **1/1**

**Approvals Summary:**
| Reviewer | Permission | Status |
|----------|------------|--------|
| @zakisk | `admin` | ✅ |



Thank you @chmouel for your valuable contribution! 🎉

*Automated by the [PAC Boussole](https://github.com/openshift-pipelines/pac-boussole) 🧭* 


author_association: NONE