Skip to content

Commit 633ac34

Browse files
authored
Merge branch 'main' into parsepayload
2 parents bd8c88e + f07a394 commit 633ac34

File tree

15 files changed

+256
-84
lines changed

15 files changed

+256
-84
lines changed

hack/mirror-pr.sh

Lines changed: 120 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,119 @@
11
#!/usr/bin/env bash
2-
# A script to mirror an external contributor's pull request to a maintainer's fork
3-
# for the purpose of running E2E tests.
42
#
5-
# Prerequisites:
6-
# 1. GitHub CLI (`gh`) must be installed and authenticated (`gh auth login`).
7-
# 2. You must have a fork of the repository.
8-
# 3. You must have a git remote configured for the upstream repository (e.g., "upstream").
9-
#
10-
# Usage:
11-
# ./mirror-pr.sh <PR_NUMBER> <FORK_REMOTE>
12-
#
13-
# Example:
14-
# ./mirror-pr.sh 1234 my-github-user
15-
#
16-
# if no PR number is provided, it will prompt you to select one using `fzf`.
3+
no_verify=
4+
show_help() {
5+
cat <<EOF
6+
🪞 Mirror an external contributor's pull request to a maintainer's fork for E2E tests.
7+
8+
🛠️ Prerequisites:
9+
1. 🐙 GitHub CLI (gh) must be installed and authenticated (gh auth login).
10+
2. 🍴 You must have a fork of the repository.
11+
3. 🔗 You must have a git remote configured for the upstream repository (e.g., "upstream").
12+
4. 👾 You need fzf and jq installed for selecting PRs and parsing JSON.
13+
14+
▶️ Usage:
15+
./mirror-pr.sh <PR_NUMBER> <FORK_REMOTE>
16+
17+
💡 Example:
18+
./mirror-pr.sh 1234 my-github-user
19+
20+
If no PR number or not fork are provided, it will prompt you to select one
21+
using fzf.
22+
23+
EOF
24+
grep -E "[ ]*[a-zA-Z0-9-]\) ##" $0 |
25+
sed -e 's/^[ ]*/-/' \
26+
-e 's/-\([0-9A-Za-z]*\)[ ]*|[ ]*\([0-9A-Za-z]*\)/-\1, -\2/' \
27+
-e 's/##//' -e 's/)[ ]*/ - /' |
28+
awk -F" - " '{printf "%-10s %s\n", $1, $2}'
29+
30+
cat <<EOF
31+
32+
EOF
33+
}
34+
while getopts "hn" opt; do
35+
case $opt in
36+
n) ## do not run pre-commit checks
37+
no_verify=yes
38+
;;
39+
h)
40+
echo "usage: $(basename $(readlink -f $0))"
41+
show_help
42+
exit 0
43+
;;
44+
*)
45+
echo "unknown option: -${OPTARG}" >&2
46+
show_help
47+
exit 1
48+
;;
49+
esac
50+
done
51+
shift $((OPTIND - 1))
1752

1853
set -eo pipefail
1954

2055
if ! command -v gh &>/dev/null; then
21-
echo "Error: GitHub CLI ('gh') is not installed. Please install it to continue."
22-
echo "See: https://cli.github.com/"
56+
echo "🛑 Error: GitHub CLI ('gh') is not installed. Please install it to continue."
57+
echo "🔗 See: https://cli.github.com/"
2358
exit 1
2459
fi
2560

26-
echo "✅ GitHub CLI is installed."
61+
echo "✅ GitHub CLI is installed. Ready to proceed!"
2762

2863
PR_NUMBER=${1:-}
2964
FORK_REMOTE=${GH_FORK_REMOTE:-$2}
3065
UPSTREAM_REPO=${GH_UPSTREAM_REPO:-"openshift-pipelines/pipelines-as-code"}
3166

32-
# Check if there is any changes in the current branch or bail out
67+
# 🛡️ Check for uncommitted changes
3368
if ! git diff-index --quiet HEAD --; then
34-
echo " Error: There are uncommitted changes in the current branch. Please commit or stash them before running this script."
69+
echo "📝 Error: There are uncommitted changes in the current branch. Please commit or stash them before running this script."
3570
exit 1
3671
fi
3772

3873
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
3974
resetgitbranch() {
4075
new_branch_name=$(git rev-parse --abbrev-ref HEAD)
41-
echo "🔄 Resetting to original branch ${CURRENT_BRANCH} from ${new_branch_name}"
76+
echo "↩️ Resetting to original branch ${CURRENT_BRANCH} from ${new_branch_name}"
4277
git checkout "$CURRENT_BRANCH" || true
4378
}
4479
trap resetgitbranch EXIT
4580

81+
# 🎯 Select PR number if not provided
4682
if [[ -z ${PR_NUMBER} ]]; then
47-
PR_SELECTION=$(gh pr list --repo "$UPSTREAM_REPO" --json number,title,author --template '{{range .}}{{.number}}: {{.title}} (by {{.author.login}})
48-
{{end}}' | grep -v "\[MIRRORED\]" | fzf --prompt="Select PR: ")
49-
PR_NUMBER=$(echo "$PR_SELECTION" | awk -F: '{print $1}' | xargs)
83+
if [[ ${CURRENT_BRANCH} =~ test-pr-([0-9]+)-([a-zA-Z0-9_-]+) ]]; then
84+
PR_NUMBER="${BASH_REMATCH[1]}"
85+
else
86+
PR_SELECTION=$(gh pr list --repo "$UPSTREAM_REPO" --json number,title,author --template '{{range .}}{{.number}}: {{.title}} (by {{.author.login}})
87+
{{end}}' | grep -v "\[MIRRORED\]" | fzf --prompt="🔎 Select PR: ")
88+
PR_NUMBER=$(echo "$PR_SELECTION" | awk -F: '{print $1}' | xargs)
89+
fi
5090
fi
5191

92+
# 🔍 Check if a mirrored PR already exists
93+
already_opened_pr=$(
94+
gh pr list --repo $UPSTREAM_REPO \
95+
--json number,headRepositoryOwner,headRepository,headRefName |
96+
jq -r --arg pn "$PR_NUMBER" \
97+
'.[] | select(.headRefName | test("^test-pr-\($pn)-.*")) | "[email protected]:\(.headRepositoryOwner.login)/\(.headRepository.name).git"'
98+
)
99+
[[ -n ${already_opened_pr} ]] && FORK_REMOTE=${already_opened_pr}
100+
101+
# 🌿 Select fork remote if not provided
52102
if [[ -z $FORK_REMOTE ]]; then
53-
FORK_REMOTE=$(git remote | awk '{print $1}' | grep -v origin | sort -u | fzf -1 --prompt="Select fork remote: ")
103+
FORK_REMOTE=$(git remote | awk '{print $1}' | grep -v origin | sort -u | fzf -1 --prompt="🌿 Select fork remote: ")
54104
fi
55105

56106
if [[ -z "$PR_NUMBER" || -z "$FORK_REMOTE" ]]; then
57-
echo "Usage: $0 <PR_NUMBER> <YOUR_REMOTE_FORK>"
58-
echo "Example: $0 1234 my-github-user"
59-
echo "UPSTREAM_REPO is ${UPSTREAM_REPO} unless you configure the env variable GH_UPSTREAM_REPO."
107+
echo "ℹ️ Usage: $0 <PR_NUMBER> <YOUR_REMOTE_FORK>"
108+
echo "💡 Example: $0 1234 my-github-user"
109+
echo "🔎 UPSTREAM_REPO is ${UPSTREAM_REPO} unless you configure the env variable GH_UPSTREAM_REPO."
60110
exit 1
61111
fi
62112

63-
# --- Main Logic ---
113+
echo "🔍 Fetching details for PR #${PR_NUMBER} from ${UPSTREAM_REPO}..."
114+
echo "🌿 Fork remote: ${FORK_REMOTE}"
64115

65-
echo "🔄 Fetching details for PR #${PR_NUMBER} from ${UPSTREAM_REPO}..."
66-
67-
# Fetch PR title and author using GitHub CLI
116+
# 📋 Fetch PR title and author
68117
PR_TITLE=$(gh pr view "$PR_NUMBER" --repo "$UPSTREAM_REPO" --json title -q .title)
69118
PR_AUTHOR=$(gh pr view "$PR_NUMBER" --repo "$UPSTREAM_REPO" --json author -q .author.login)
70119
PR_URL="https://github.com/${UPSTREAM_REPO}/pull/${PR_NUMBER}"
@@ -74,71 +123,77 @@ if [[ -z "$PR_TITLE" ]]; then
74123
exit 1
75124
fi
76125

77-
echo " - Title: $PR_TITLE"
78-
echo " - Author: $PR_AUTHOR"
126+
echo "📝 - Title: $PR_TITLE"
127+
echo "👤 - Author: $PR_AUTHOR"
79128

80-
# 1. Checkout the PR locally
81-
echo "🔄 Checking out PR #${PR_NUMBER} locally..."
129+
# 1️⃣ Checkout the PR locally
130+
echo "📥 Checking out PR #${PR_NUMBER} locally..."
82131
gh pr checkout --force "$PR_NUMBER" --repo "$UPSTREAM_REPO"
83132

84-
# 2. Push the branch to your fork
133+
# 2️⃣ Push the branch to your fork
85134
NEW_BRANCH_NAME="test-pr-${PR_NUMBER}-${PR_AUTHOR}"
86135

87-
# check if we didn't already have a pull request open for this branch
88-
already_opened_pr=$(
89-
gh pr list --repo "$UPSTREAM_REPO" --head \
90-
"${NEW_BRANCH_NAME}" --json url --jq '.[0].url'
91-
)
92-
93136
if [[ -n ${already_opened_pr} ]]; then
94-
echo "🔄 A pull request already exists for this branch, pushing to the pull request target: ${already_opened_pr}"
95-
96-
gh pr list --repo openshift-pipelines/pipelines-as-code --head ${NEW_BRANCH_NAME} --json headRepositoryOwner,headRepository --jq '.[0].headRepositoryOwner.login + "/" + .[0].headRepository.name'
97-
)"
98-
echo "🔨 Pushing changes to existing pull request branch '${NEW_BRANCH_NAME}' fork (${FORK_REMOTE})..."
137+
echo "🔁 A pull request already exists for this branch, pushing to the pull request target: ${already_opened_pr}"
138+
echo "🚚 Pushing changes to existing pull request branch '${NEW_BRANCH_NAME}' fork (${FORK_REMOTE})..."
99139
else
100-
101-
echo "🔨 Pushing changes to a new branch '${NEW_BRANCH_NAME}' on your fork (${FORK_REMOTE})..."
140+
echo "🚀 Pushing changes to a new branch '${NEW_BRANCH_NAME}' on your fork (${FORK_REMOTE})..."
102141
fi
103142

104-
# Force push in case the branch already exists from a previous test run
105-
git push "$FORK_REMOTE" "HEAD:${NEW_BRANCH_NAME}" --force
143+
# 🚨 Force push in case the branch already exists from a previous test run
144+
if [[ -n ${no_verify} ]]; then
145+
echo "⚠️ Skipping pre-push verification due to --no-verify flag."
146+
else
147+
if ! command -v "pre-commit" >/dev/null 2>&1; then
148+
echo "⚠️ You need to have the 'pre-commit' tool installed to run this script."
149+
exit 1
150+
fi
151+
echo "🚜 Running pre-commit checks before pushing..."
152+
pre-commit run --all-files --show-diff-on-failure || {
153+
echo "❗ Pre-commit checks failed. Please fix the issues before pushing."
154+
echo "You can fix user errors locally and pushing to the user branch."
155+
echo "git commit --amend the commit (or add a new commit) and then run this command"
156+
gh pr view "$PR_NUMBER" --repo "$UPSTREAM_REPO" --json headRefName,headRepositoryOwner,headRepository |
157+
jq -r '"git push --force-with-lease [email protected]:\(.headRepositoryOwner.login)/\(.headRepository.name).git HEAD:\(.headRefName)"'
158+
echo "(or use --force if you know what you are doing)"
159+
exit 1
160+
}
161+
fi
162+
git push "$FORK_REMOTE" "HEAD:${NEW_BRANCH_NAME}" --force --no-verify
106163

107164
if [[ -n ${already_opened_pr} ]]; then
108-
echo "🔗 Pull request has successfully been synched ${already_opened_pr}"
109165
exit 0
110166
fi
111167

112-
# 3. Create a new Pull Request from the fork to the upstream repo
113-
MIRRORED_PR_TITLE="[MIRRORED] ${PR_TITLE}"
114-
MIRRORED_PR_BODY="Mirrors ${PR_URL} to run E2E tests. Original author: @${PR_AUTHOR}"
168+
# 3️⃣ Create a new Pull Request from the fork to the upstream repo
169+
MIRRORED_PR_TITLE="🪞 [MIRRORED] ${PR_TITLE}"
170+
MIRRORED_PR_BODY="🔄 Mirrors ${PR_URL} to run E2E tests. Original author: @${PR_AUTHOR}"
115171
DO_NOT_MERGE_LABEL="do-not-merge" # You might need to create this label in your repo if it doesn't exist
116172

117-
echo "🔄 Creating a new mirrored pull request on ${UPSTREAM_REPO}..."
173+
echo "🆕 Creating a new mirrored pull request on ${UPSTREAM_REPO}..."
118174

119-
# Create the PR as a draft to prevent accidental merges before tests run.
120-
# The --head flag specifies the branch in your fork.
175+
# 📝 Create the PR as a draft to prevent accidental merges before tests run.
121176
CREATED_PR_URL=$(gh pr create \
122177
--repo "$UPSTREAM_REPO" \
123178
--title "$MIRRORED_PR_TITLE" \
124179
--body "$MIRRORED_PR_BODY" \
125180
--head "${FORK_REMOTE}:${NEW_BRANCH_NAME}" \
126181
--label "$DO_NOT_MERGE_LABEL" \
127-
--draft) # Using --draft is safer
182+
--draft)
128183

129-
# Check if the PR was created successfully
184+
# Check if the PR was created successfully
130185
if [[ -z "$CREATED_PR_URL" ]]; then
131-
echo " Error: Failed to create the mirrored pull request."
186+
echo " Error: Failed to create the mirrored pull request."
132187
exit 1
133188
fi
134189

135190
gh pr comment "$PR_NUMBER" --repo "$UPSTREAM_REPO" --body \
136-
":rocket: **Mirrored PR Created for E2E Testing**<br><br>\
191+
"🚀 **Mirrored PR Created for E2E Testing**<br><br>\
137192
A mirrored PR has been opened for end-to-end testing: [View PR](${CREATED_PR_URL})<br><br>\
138-
:hourglass_flowing_sand: Follow progress there for E2E results.<br>\
193+
Follow progress there for E2E results.<br>\
139194
If you need to update the PR with new changes, please ask a maintainer to rerun \`hack/mirror-pr.sh\`."
140195

141-
echo " Successfully created mirrored pull request!"
196+
echo "🎉 Successfully created mirrored pull request!"
142197
echo " ${CREATED_PR_URL}"
143198

144-
echo "🚀 Done."
199+
echo "🏁 Done."

pkg/provider/bitbucketcloud/bitbucket.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,10 @@ func (v *Provider) SetClient(_ context.Context, run *params.Run, event *info.Eve
203203
return fmt.Errorf("no git_provider.user has been in repo crd")
204204
}
205205
v.bbClient = bitbucket.NewBasicAuth(event.Provider.User, event.Provider.Token)
206+
207+
// Added log for security audit purposes to log client access when a token is used
208+
run.Clients.Log.Infof("bitbucket-cloud: initialized client with provided token for user=%s", event.Provider.User)
209+
206210
v.Token = &event.Provider.Token
207211
v.Username = &event.Provider.User
208212
v.run = run

pkg/provider/bitbucketcloud/bitbucket_test.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package bitbucketcloud
22

33
import (
4+
"fmt"
45
"strings"
56
"testing"
67

78
"github.com/ktrysmt/go-bitbucket"
89
"github.com/openshift-pipelines/pipelines-as-code/pkg/params"
10+
"github.com/openshift-pipelines/pipelines-as-code/pkg/params/clients"
911
"github.com/openshift-pipelines/pipelines-as-code/pkg/params/info"
1012
"github.com/openshift-pipelines/pipelines-as-code/pkg/params/settings"
1113
"github.com/openshift-pipelines/pipelines-as-code/pkg/params/triggertype"
@@ -145,14 +147,29 @@ func TestSetClient(t *testing.T) {
145147
for _, tt := range tests {
146148
t.Run(tt.name, func(t *testing.T) {
147149
ctx, _ := rtesting.SetupFakeContext(t)
150+
core, observer := zapobserver.New(zap.InfoLevel)
151+
testLog := zap.New(core).Sugar()
152+
153+
fakeRun := &params.Run{
154+
Clients: clients.Clients{
155+
Log: testLog,
156+
},
157+
}
158+
148159
v := Provider{}
149-
err := v.SetClient(ctx, nil, tt.event, nil, nil)
160+
err := v.SetClient(ctx, fakeRun, tt.event, nil, nil)
161+
150162
if tt.wantErrSubstr != "" {
151163
assert.ErrorContains(t, err, tt.wantErrSubstr)
152164
return
153165
}
154166
assert.Equal(t, tt.event.Provider.Token, *v.Token)
155167
assert.Equal(t, tt.event.Provider.User, *v.Username)
168+
169+
logs := observer.TakeAll()
170+
assert.Assert(t, len(logs) > 0, "expected a log entry, got none")
171+
expected := fmt.Sprintf("bitbucket-cloud: initialized client with provided token for user=%s", tt.event.Provider.User)
172+
assert.Equal(t, expected, logs[0].Message)
156173
})
157174
}
158175
}

pkg/provider/bitbucketdatacenter/bitbucketdatacenter.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,9 @@ func (v *Provider) SetClient(ctx context.Context, run *params.Run, event *info.E
307307
},
308308
}
309309
v.client = client
310+
311+
// Added for security audit purposes to log client access when a token is used
312+
run.Clients.Log.Infof("bitbucket-datacenter: initialized client with provided token for user=%s providerURL=%s", event.Provider.User, event.Provider.URL)
310313
}
311314
v.run = run
312315
v.repo = repo

pkg/provider/bitbucketdatacenter/bitbucketdatacenter_test.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"testing"
1616

1717
"github.com/openshift-pipelines/pipelines-as-code/pkg/params"
18+
"github.com/openshift-pipelines/pipelines-as-code/pkg/params/clients"
1819
"github.com/openshift-pipelines/pipelines-as-code/pkg/params/info"
1920
"github.com/openshift-pipelines/pipelines-as-code/pkg/params/settings"
2021
"github.com/openshift-pipelines/pipelines-as-code/pkg/params/triggertype"
@@ -362,14 +363,21 @@ func TestSetClient(t *testing.T) {
362363
}
363364
for _, tt := range tests {
364365
t.Run(tt.name, func(t *testing.T) {
366+
observer, _ := zapobserver.New(zap.InfoLevel)
367+
testLog := zap.New(observer).Sugar()
368+
fakeRun := &params.Run{
369+
Clients: clients.Clients{
370+
Log: testLog,
371+
},
372+
}
365373
ctx, _ := rtesting.SetupFakeContext(t)
366374
client, mux, tearDown, tURL := bbtest.SetupBBDataCenterClient()
367375
defer tearDown()
368376
if tt.muxUser != nil {
369377
mux.HandleFunc("/users/foo", tt.muxUser)
370378
}
371379
v := &Provider{client: client, baseURL: tURL}
372-
err := v.SetClient(ctx, nil, tt.opts, nil, nil)
380+
err := v.SetClient(ctx, fakeRun, tt.opts, nil, nil)
373381
if tt.wantErrSubstr != "" {
374382
assert.ErrorContains(t, err, tt.wantErrSubstr)
375383
return

pkg/provider/gitea/gitea.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,10 @@ func (v *Provider) SetClient(_ context.Context, run *params.Run, runevent *info.
159159
if err != nil {
160160
return err
161161
}
162+
163+
// Added log for security audit purposes to log client access when a token is used
164+
run.Clients.Log.Infof("gitea: initialized API client with provided credentials user=%s providerURL=%s", runevent.Provider.User, apiURL)
165+
162166
v.giteaInstanceURL = runevent.Provider.URL
163167
v.eventEmitter = emitter
164168
v.repo = repo

pkg/provider/github/github.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,13 @@ func (v *Provider) SetClient(ctx context.Context, run *params.Run, event *info.E
301301
return fmt.Errorf("no github client has been initialized")
302302
}
303303

304+
// Added log for security audit purposes to log client access when a token is used
305+
integration := "github-webhook"
306+
if event.InstallationID != 0 {
307+
integration = "github-app"
308+
}
309+
run.Clients.Log.Infof(integration+": initialized OAuth2 client for providerName=%s providerURL=%s", v.providerName, event.Provider.URL)
310+
304311
v.APIURL = apiURL
305312

306313
if event.Provider.WebhookSecretFromRepo {

0 commit comments

Comments
 (0)