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

Verify that PR creator is a member of the website-write team #6971

Open
wants to merge 15 commits into
base: gh-pages
Choose a base branch
from

Conversation

ajb176
Copy link
Member

@ajb176 ajb176 commented Jun 7, 2024

Fixes #3906

What changes did you make?

  • Added a new workflow which makes up to three API calls to verify team membership, close the pull request, and add the requested comment (the latter two if necessary).
  • The octokit membership API call returns a 404 error if the member is not found on the website-write team, in which case the catch block makes the API calls to close the PR and add the comment.
  • If the PR author is found on the website-write team (the expected case), nothing will happen except a comment logged that the author was successfully verified.

Why did you make the changes (we will use this info to test)?

  • To ensure only members of the website-write team can create pull requests.

Instructions for Reviewers:

  • 1. Add - 'verify-pr-creator-3906' on line 7 aligned with and under the 'gh-pages' branch
  • 2. Replace the current token value on line 14 with a user-generated token with the same permissions as the HACKFORLA_ADMIN_TOKEN (Instructions here)
  • 3. Change the owner assignment on lines 28 and 34 from 'hackforla' to your own github handle
  • 4. Save, commit and push the changes to your local verify-pr-creator-3906 branch
  • 5. Checkout a new branch from this one (testcase1, for example), make any minor change (add a comment for example), then commit and push it
  • 6. Go to your github website fork and try to merge testcase1 into the verify-pr-creator-3906 branch
  • 7. The github actions should start running (assuming the base is the verify-pr-creator-3906 branch edited from steps 1-4)
  • 8. There should be a checkmark if the action was successful, click details, dropdown the RunActions/GithubScript and it should say 'Successfully verified!'
  • 9. For testing the fail condition, navigate back to the verify-pr-creator branch and change the username assignment from prAuthor in line 22 to a random string or github handle of someone not on the website-write team.
  • 10. Repeat steps 4-8 (for step 5 you can call the new branch testcase2), this time the pull request should automatically close and post a comment from your handle

Make sure to push the necessary changes to the verify-pr-creator branch before using checkout to create the testcase branches. The testcase branches should be one commit past the verify-pr branch to avoid headaches when trying to merge the testcase branch into the base branch. If you'd rather not mess with the original branch, you can also checkout a new branch immediately after pulling the verify-pr-creator-3906 branch, and follow the instructions while using the new branch name in steps 1, 4, 6, 7 and 9.

@HackforLABot HackforLABot added this to PR Needs review (Automated Column, do not place items here manually) in Project Board Jun 7, 2024
Copy link

github-actions bot commented Jun 7, 2024

Want to review this pull request? Take a look at this documentation for a step by step guide!


From your project repository, check out a new branch and test the changes.

git checkout -b ajb176-verify-pr-creator-3906 gh-pages
git pull https://github.com/ajb176/website.git verify-pr-creator-3906

@github-actions github-actions bot added role: back end/devOps Tasks for back-end developers Complexity: Large Status: Updated No blockers and update is ready for review Feature: Board/GitHub Maintenance Project board maintenance that we have to do repeatedly automation for manulal github board maintenance actions that are going to be automated size: 3pt Can be done in 13-18 hours labels Jun 7, 2024
@ajb176 ajb176 marked this pull request as ready for review June 7, 2024 15:03
@github-actions github-actions bot removed the Status: Updated No blockers and update is ready for review label Jun 8, 2024
@t-will-gillis t-will-gillis self-requested a review June 10, 2024 03:21
@t-will-gillis
Copy link
Member

availability:
eta: 6/16 e.o.d.

@moazDev1
Copy link
Member

Availability: Weekdays 5PM - 9PM
ETA: 6/23 EOD

Copy link
Member

@t-will-gillis t-will-gillis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @ajb176 Great job with this- I tested in my repo with both a my name and a non-hfla name. The PR authored by the non-member was closed and the message was posted on the issue. So everything works well.

I have some comments:

  • I think that I could see this both ways, but here is the question: did you consider adding this as another job in the pull-request-trigger.yml workflow? It seems this job could belong there, but the counter-argument is that pr-instructions.yml is independent so why not this one?
  • Regarding the job itself, there are other times that we need to check team membership and I believe that this should be pulled into a javascript file in the utils folder, check-team-membership.js or something. Then we can reuse this module in other workflows.
  • Assuming that you do create the js file, owner could be defined in terms of context.repo.owner and repo in terms of context.repo.repo
  • minor thing, but notice you are using the earlier version of the API on line 19 with await github.rest.teams.getMembershipForUserInOrg instead of the current version similar to lines 27 and 33., e.g. await github.request('GET /orgs/{org}/teams/{team_slug}/memberships/{username}
  • (FYI we might(???) need to convert the API over to GraphQL in several months. But not worrying about that right now...)

Again, everything is looking good and thanks for working on this!

Project Board automation moved this from PR Needs review (Automated Column, do not place items here manually) to test-pending-approval (Automated Column, do not place items here manually) Jun 15, 2024
@ajb176
Copy link
Member Author

ajb176 commented Jun 15, 2024

Hey @t-will-gillis, thanks for the feedback.

  • Using the pull-request-trigger.yml was my first thought, but that trigger also fires when the PR is closed, this job only needs to run once when the PR is opened. I'm under the impression that separate yml files should generally be used for different triggers, and technically a better name for the yml I created would be pull-request-target-open.yml, and it could be changed to that if there are any other jobs we want to add specifically when a PR is opened and access is needed. One thing that's confusing to me is I didn't catch any mention of tokens in the pr-instructions and wr-pr-instructions workflow, so I'm not sure how they obtain permission to post comments (I might just be missing something). Any idea about that?
  • Nice catch with the API, I forgot about that. There's no good reason why I used both, I was using the docs here: https://octokit.github.io/rest.js/v20#usage and was looking for a method to close pull requests and couldn't find one. Because the docs here https://docs.github.com/en/rest/pulls/pulls?apiVersion=2022-11-28 have the API calls specifically grouped for each type I found them a little easier to read. What I didn't notice was that you treat PRs just like issues and I should've been looking for an API call to update issues and not specifically PRs. I believe they use the same API endpoints, the rest calls are just a little more intuitive to use because they abstract out the HTTP and look like normal JS functions. I can switch the API calls to either syntax, there should be a matching one for each and they should function exactly the same way.

Regarding the job itself, there are other times that we need to check team membership and I believe that this should be pulled into a javascript file in the utils folder, check-team-membership.js or something. Then we can reuse this module in other workflows.

Do you mean the entire job, or just get membership API call? I'm not sure if I see much re-usability in the script here, beyond discretizing the API calls themselves which wouldn't make much sense. Can you expand on this a little?

@t-will-gillis
Copy link
Member

Hey @ajb176

  • About whether your workflow should be part of “Pull Request Trigger” or not: we currently have three PR related workflows and we could gather these plus your workflow into one big happy PR workflow, but I am leaning towards the argument that keeping these as separate workflows might be a better idea. But since we keep adding new workflows, I do think we need to have a standard naming convention. Naming your workflow as pr-verification.yml or similar works for me- since it aligns with pr-instructions.yml. Maybe the last one should be pr-set-labels.yml? I am thinking that it would be ideal to look at the files and see right away which workflows have the same triggers.
  • About pr-instructions.yml and wr-pr-instructions.yml not having explicitly defined tokens, they are using default access permissions. I can’t claim that I know this topic inside and out, but here is an article. When you look at “Set up job” in an “Add Pull Request Instructions” workflow run, there is a default GITHUB_TOKEN and permissions.
  • About the v20 versus version=2022-11-28, yeah I agree that they would function exactly the same way, but thought it would be cleaner to use the later version for all.
  • About creating the JS file, I was meaning the entire job. You would still have the yml file- it would be similar to “Add-Missing-Labels-To-Issues” (f. “Issue Trigger”) in its organizational structure , but it would run a /utils/ file similar to get-team-members.js to check if the individual was on the team, that would trigger the existing utils/post-issue-comment.js when needed. Modularized.
  • Let me know if you would like to discuss more…
  • BTW on the “Issue Trigger” workflow we are checking team membership using someone else’s automation. It would be good to use our own checks so we aren't at the mercy of the person keeping their automation updated.

@ajb176
Copy link
Member Author

ajb176 commented Jun 17, 2024

  • It seems like there isn't a clean way to group together jobs with different but similar triggers. All I could find is using some if statements to evaluate context variables, and using the value of those context variables to determine whether the job should run. Kind of a roundabout method to do something that should be pretty simple. It seems like the trigger is the important thing that determines whether jobs can be within the same workflow, but the triggers are all different now anyway, which is why I suggested keeping the current naming convention until more jobs with the same trigger are added, in which case we can re-name it to the trigger so people can know immediately whether a new job they're writing can fit there. I'm not sure what the overhead of having multiple yml files vs multiple jobs in a yml file is, maybe someone can look into that. If it's not really a concern to have a ton of yml files, what we're doing now seems fine.
  • I think you're right, thanks. I'm surprised you're able to post comments with the default token.
  • Yeah, no what I mean to say is they're both the current version. See here. The .rest methods are built on top of the .request methods to make them easier to use. I've seen mostly .request being used withinin yml files, the post-comment script uses the .rest method. Both are linked in the wiki, if we want to use one we should probably remove the link to the other. I would prefer to use the rest methods seeing as they're made for convenience and I see no reason not to, but I'm not hung up on either.
  • I can make a util function that takes a function as a parameter, runs the membership check, and only calls the function if the check passes. My concern is just readability, it's pretty easy to see how the action works right now and I don't want to obfuscate a very simple script by splitting it up into too many different files that then import functions from more files. I can definitely move the full script to a JS file and make a utility function that checks membership though, I'll check the issue-trigger and make sure the util function can fit there.

@ExperimentsInHonesty ExperimentsInHonesty added role: back end and removed role: back end/devOps Tasks for back-end developers labels Jun 18, 2024
@ajb176
Copy link
Member Author

ajb176 commented Jun 21, 2024

Hey @t-will-gillis

I have a working version of this that has a utility function that checks membership, a script that calls that utility function and completes the action, and a yml file that calls that script. That being said, I think something closer to the version here is better.

The biggest concern here is the pull_request_trigger. It's a pretty invasive trigger that works within the base of the pull request and has access to repository secrets. If I want to call a script I have to use actions/checkout, which creates a context in which an attacker could potentially have access to all repository files, and access to all repository secrets. Using checkout makes it possible to hide some malicious code abstracted away through several different modules. Considering this is easily avoided by modifying only the yml file and keeping everything it does in plain sight, I think it's a better idea to not use checkout in the pull_request_target unless absolutely necessary. Any code run within the context of pull_request_target will have to be very carefully examined before even checking out the branch for testing, and it will be easier to do that if it's fully contained in a yml file with no access to any other files/scripts. Using checkout also adds another dependency and will take a little longer to run

I'd suggest keeping the yml file as is (after making the syntax for the API calls uniform), but I can add the utility function from the other branch that checks membership in case it would be useful for other actions. I can make a draft PR with the other implementation if you'd like to take a look and test the utility function.

@t-will-gillis
Copy link
Member

t-will-gillis commented Jun 27, 2024

@ajb176 Thank you for bringing up the topic about the potential security risks of using actions/checkout with pull_request_target. This is something we will need to watch for and avoid in the future.

I tested the current code, and a non-hfla user was able to post a PR still. (This could be because the non-member returns a “RequestError” and not a “VerificationError”?)

I hear what you are saying about not making things more complicated than needed. I would argue however that this workflow is more complicated than it needs to be. As written currently, this workflow is doing three things in a single step (checking membership; if not a member, then closing the PR; if closing the PR, then commenting on the PR).

Please see Hack for LA’s GitHub Actions HfLA’s workflows follow a patten of an event triggering a yaml file in .github/ directory, the yaml performs a series of steps and calls js files in the github-actions/ directory. This is not the only way to do things and we break this pattern sometimes.

Please move the full script to the js file. This workflow can be written in an easy to follow pattern similar to pr-instructions.yml. That is, using pull-request with actions/checkout and running a script. Note that this does not require using a token. Besides following the pattern of our other workflows, this lets us modularize repetitive actions including checking team membership and writing a comment to a PR/issue.

Therefore please:

  • break up the yaml file and follow the pattern used in our other workflows, especially pr-instructions.yml,
  • address the main error noted above,
  • rewrite variables so they do not need to be hard-coded, eg. owner: ‘hackforla’ should be owner: context.repo.owner, etc. , and
  • although this isn’t on the original issue, please capitalize “GitHub” and “Slack” in any comments so that we do not need to fix this in a later issue.

Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
automation for manulal github board maintenance actions that are going to be automated Complexity: Large Feature: Board/GitHub Maintenance Project board maintenance that we have to do repeatedly role: back end size: 3pt Can be done in 13-18 hours
Projects
Status: test-pending-approval (Automated Column, do not place items here manually)
Project Board
  
test-pending-approval (Automated Colu...
Development

Successfully merging this pull request may close these issues.

Create a Github Action to verify Pull Requests are created by website team members
4 participants