Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change tagbot workflow to run on pull_request_target and comment on security #21779

Merged
merged 24 commits into from
Nov 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
2865dbc
Change tagbot workflow to run on pull_request_target
Micket Nov 1, 2024
d2f33da
Add comments describing permissions on tagbot
Micket Nov 1, 2024
2ac4ad4
Try using conditional workflow based on if tagbot is modified.
Micket Nov 1, 2024
3aed346
Add debug printout temporarily
Micket Nov 1, 2024
910b530
Add checkout of PR commit
Micket Nov 1, 2024
29232d7
Fix tagbot.py to use merge commit sha when diffing
Micket Nov 1, 2024
3572045
Fix typo
Micket Nov 1, 2024
61d3f6e
Fix missing printout in tagbot
Micket Nov 1, 2024
229223c
Add additional label for workflow changes, to highlight for reviewers
Micket Nov 1, 2024
02bfe0a
Rework yml, only run when no merge conflict, fix possible security hole
Micket Nov 2, 2024
f8180ea
Add target commit sha for debuggin
Micket Nov 2, 2024
8668891
Print out github event data for debugging
Micket Nov 2, 2024
b2fb3c9
Switch to manually attempting merge due to github race condition with
Micket Nov 3, 2024
9772d14
Add concurrency to prevent conflicting tags/comments
Micket Nov 3, 2024
baaa8ba
Remove unsused import
Micket Nov 3, 2024
58debaa
Add quotes around concurrency group
Micket Nov 3, 2024
16ac316
Fix indentation
Micket Nov 3, 2024
b0f49b9
Make steps more explicit, perform merge in pr subdir
Micket Nov 3, 2024
51dd49e
Add missing linebreak on code blocks
Micket Nov 3, 2024
e9f42fe
Make stdoutput nicer, display merge commit sha
Micket Nov 3, 2024
40ca1dd
Add git name/email for temporary merge test
Micket Nov 3, 2024
4c021b4
Fix string conversion for printout
Micket Nov 3, 2024
0318112
Drop very verbose debug output of event data
Micket Nov 4, 2024
ca81bd8
Update .github/workflows/tagbot.yml
ocaisa Nov 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 31 additions & 31 deletions .github/workflows/tagbot.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
# NOTE: In order to write comment and edit labels, this script requires workflows with write permissions.
# It should not use any untrusted third party code, or any code checked into the repository itself
# as that could indirectly grant PRs the ability to edit labels and comments on PRs.

import os
import git
import requests
import json
import difflib
from datetime import datetime
from pathlib import Path


Expand All @@ -12,8 +14,7 @@ def get_first_commit_date(repo, file_path):
if commits:
return commits[-1].committed_date
else:
print(f"{file_path} has no commit info, putting it last")
return datetime.datetime.min
raise ValueError(f'{file_path} has no commit info, this should not happen')


def sort_by_added_date(repo, file_paths):
Expand All @@ -27,17 +28,6 @@ def similar_easyconfigs(repo, new_file):
return sort_by_added_date(repo, possible_neighbours)


def diff(old, new):
with open(old, 'r') as old_file, open(new, 'r') as new_file:
old_lines = list(old_file)
new_lines = list(new_file)
return ''.join(difflib.unified_diff(
old_lines,
new_lines,
fromfile=str(old),
tofile=str(new)))


def pr_ecs(pr_diff):
new_ecs = []
changed_ecs = []
Expand All @@ -51,33 +41,38 @@ def pr_ecs(pr_diff):


GITHUB_API_URL = 'https://api.github.com'
event_path = os.getenv("GITHUB_EVENT_PATH")
token = os.getenv("GH_TOKEN")
repo = os.getenv("GITHUB_REPOSITORY")
base_branch_name = os.getenv("GITHUB_BASE_REF")
pr_ref_name = os.getenv("GITHUB_REF_NAME")
event_path = os.getenv('GITHUB_EVENT_PATH')
token = os.getenv('GH_TOKEN')
repo = os.getenv('GITHUB_REPOSITORY')
base_branch_name = os.getenv('GITHUB_BASE_REF')

with open(event_path) as f:
data = json.load(f)

pr_number = data['pull_request']['number']
# Can't rely on merge_commit_sha for pull_request_target as it might be outdated
# merge_commit_sha = data['pull_request']['merge_commit_sha']

print("PR number:", pr_number)
print("Repo:", repo)
print("Base branch name:", base_branch_name)
print("PR ref:", pr_ref_name)

gitrepo = git.Repo(".")

# Change into "pr" checkout directory to allow diffs and glob to work on the same content
os.chdir('pr')
gitrepo = git.Repo('.')

target_commit = gitrepo.commit('origin/' + base_branch_name)
pr_commit = gitrepo.commit('pull/' + pr_ref_name)
pr_diff = target_commit.diff(pr_commit)
print("Target commit ref:", target_commit)
merge_commit = gitrepo.head.commit
print("Merge commit:", merge_commit)
pr_diff = target_commit.diff(merge_commit)

new_ecs, changed_ecs = pr_ecs(pr_diff)
modified_workflow = any(item.a_path.startswith('.github/workflows/') for item in pr_diff)


print("Changed ECs:", changed_ecs)
print("Newly added ECs:", new_ecs)
print("Changed ECs:", ', '.join(str(p) for p in changed_ecs))
print("Newly added ECs:", ', '.join(str(p) for p in new_ecs))
print("Modified workflow:", modified_workflow)

new_software = 0
updated_software = 0
Expand Down Expand Up @@ -116,15 +111,20 @@ def pr_ecs(pr_diff):
comment += f'<summary>Diff against <code>{neighbour.name}</code></summary>\n\n'
comment += f'[{neighbour}](https://github.com/{repo}/blob/{base_branch_name}/{neighbour})\n\n'
comment += '```diff\n'
comment += diff(neighbour, new_file)
comment += '```\n</details>\n\n'
comment += gitrepo.git.diff(f'HEAD:{neighbour}', f'HEAD:{new_file}')
comment += '\n```\n</details>\n\n'

print("Adjusting labels")
current_labels = [label['name'] for label in data['pull_request']['labels']]

label_checks = [(changed_ecs, 'change'),
(new_software, 'new'),
(updated_software, 'update'),
(modified_workflow, 'workflow')]

labels_add = []
labels_del = []
for condition, label in [(changed_ecs, 'change'), (new_software, 'new'), (updated_software, 'update')]:
for condition, label in label_checks:
if condition and label not in current_labels:
labels_add.append(label)
elif not condition and label in current_labels:
Expand Down
34 changes: 29 additions & 5 deletions .github/workflows/tagbot.yml
Original file line number Diff line number Diff line change
@@ -1,19 +1,43 @@
name: Tagbot
on: [pull_request]
on: [pull_request_target]

concurrency:
group: "${{ github.workflow }}-${{ github.ref }}"
cancel-in-progress: true

jobs:
tagbot:
# Note: can't rely on github.event.pull_request.merge_commit_sha because pull_request_target
# does not wait for github mergability check, and the value is outdated.
# Instead we merge manually in a temporary subdir "pr"
runs-on: ubuntu-24.04
permissions:
pull-requests: write
steps:
- uses: actions/checkout@v4
- name: Checkout base branch for workflow scripts
uses: actions/checkout@v4

- name: Checkout PR for computing diff into "pr" subdirectory
uses: actions/checkout@v4
with:
ref: "${{ github.event.pull_request.head.sha }}"
path: 'pr'
fetch-depth: 0

- name: Attempt test merge
id: merge
run: |
git config user.name "github-workflow"
git config user.email "github-workflow@github.com"
git merge --no-commit --no-ff origin/${{ github.event.pull_request.base.ref }}
continue-on-error: true
working-directory: pr

- run: |
# Make sure the script is unmodified
echo "8be2d295e8436ce557acc8a4d3b82a639913ae65de0d1a76871f21359b4e8d9f .github/workflows/tagbot.py"|sha256sum --check --status
- name: Abort if merge failed
if: steps.merge.outcome == 'failure'
run: |
echo "Merge conflict detected, failing job."
exit 1

- name: set up Python
uses: actions/setup-python@v5
Expand Down
Loading