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

Fix: update release workflow to follow pypa and pypi guidelines #73

Merged
merged 15 commits into from
Mar 5, 2025

Conversation

lwasser
Copy link
Member

@lwasser lwasser commented Jan 8, 2025

this closes #48 We've been working with the pypa and pypi security folks on our blog post and this pr should address the suggested approaches to publishing using a release based workflow.

Because we are using a release, this assumes that tests are running on the main branch before a release is made. It also allows a dynamic maintainer team to make releases without the command line which is really nice.

NOTE: i haven't yet tested this specific file for issues. i'm not quite sure how - maybe via test pypi?

README.md Outdated
@@ -44,6 +44,22 @@ To use this template:
as your source. You can read more about generating your project
in the [copier documentation](https://copier.readthedocs.io/en/stable/generating/).

## How to run the test suite locally
Copy link
Member Author

Choose a reason for hiding this comment

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

Friends, bare with me on the instructions. I'm still getting to know copier and am wrapping my head around the test suite works. it seems great as it caught some spacing issues in my workflow! I just don't fully understand it yet so if any of this isn't quite right please say the word!

@lwasser
Copy link
Member Author

lwasser commented Feb 6, 2025

i'd love review on this (but also see a merge conflict now that i just merged the other pr!! a few points of potential contention

  • maybe we do want tests to run before a release ? The path i've always taken is - submit a small pr with the changelog cleanup. if that passes, merge then create a release. Perhaps that is not as robust as the tests running on the release workflow itself.
  • I just learned that you can also assign an environment permissions. so pypa now suggests that you set credentials on the push to pypi step so a human has to approve the actual publish part.

id love your feedback here all @sneakers-the-rat @blink1073 @Midnighter i'd llike to get our template nailed down for spring workshops and then scipy if we get accepted!

environment:
name: pypi
# Modify the url to be the name of your package
url: https://pypi.org/p/yourPackage
Copy link
Contributor

Choose a reason for hiding this comment

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

We should be able to template this line, right?

Copy link
Member Author

Choose a reason for hiding this comment

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

you are right! I forgot about that. I still need to learn more about how this works with copier. i'll update the PR this week.

Copy link
Contributor

@Midnighter Midnighter left a comment

Choose a reason for hiding this comment

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

Suggested a few minor things. With what you intend to do, it makes sense to turn the release pipeline into a templated file and use copier values to fill in the information. That's the bigger change.

Comment on lines 9 to 14
jobs:
prerequisites:
uses: ./.github/workflows/test.yml

release:
needs: [prerequisites]
Copy link
Contributor

Choose a reason for hiding this comment

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

This part was responsible for running the test suite before publishing. And running the release job only when the test suite is successful. It sounds like you want that kind of behaviour (and I agree it's a good idea), just add these lines again to the jobs.

Copy link
Member Author

Choose a reason for hiding this comment

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

i'm torn here. i LIKE this approach as it is robust. I like it best from a learning standpoint because it adds complexity to the CI job - we are calling a CI job within a CI job (reusable workflows), which is another concept for people to learn who may just be learning about tests and CI in general. I'm curious what @agriyakhetarpal and thinks about this.

weighing complexity for those new to packaging vs. a robust release process.

also pinging @ucodery @willingc on this one as it's part education, part packaging complexity but beyond packaging it's CI complexity. cognative load x 3.

Copy link
Member Author

Choose a reason for hiding this comment

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

I think i've been convinced that this approach reduces cognative load as it allows a user to just rerun tests on release. i'll fix my change.

Copy link
Member

Choose a reason for hiding this comment

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

I like it best from a learning standpoint because it adds complexity to the CI job - we are calling a CI job within a CI job (reusable workflows), which is another concept for people to learn who may just be learning about tests and CI in general. I'm curious what @agriyakhetarpal and thinks about this.

weighing complexity for those new to packaging vs. a robust release process.

I would be okay with such a mechanism. However, running the tests (from a built wheel, that is) is something that I've seen more commonly used with compiled packages, and can be generally overkill with pure Python packages, especially when intended for a tutorial for beginners. I'll leave it up to you to remove or keep it. :D

name: >-
Publish Python 🐍 distribution 📦 to PyPI
# Modify the repo name below to be your project's repo name.
if: github.repository_owner == 'pyopensci'
Copy link
Contributor

Choose a reason for hiding this comment

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

Looks to me like we need to enable templating for this workflow and insert the organization/repo owner here.

Copy link
Member Author

Choose a reason for hiding this comment

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

This has been fixed locally! i didn't understand copier at first but now I get the jinja templating !!

Copy link
Member

@agriyakhetarpal agriyakhetarpal left a comment

Choose a reason for hiding this comment

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

Thanks, @lwasser! This looks great; as promised, here's a review. I've tried to express my thought process with my suggestions, but please feel free to push back on them as you feel fit, especially for a template that's oriented towards a tutorial. Most of these comments are security-focused.

Comment on lines 12 to 13
# This ensures that the publish action only runs in the main repository
# rather than forks
Copy link
Member

Choose a reason for hiding this comment

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

I assume that an if: condition was probably removed from here, and the comment is a remnant?

Copy link
Member Author

Choose a reason for hiding this comment

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

oooh yes likely that was the case!! i put the publish step into it's own independent step for security!


- name: Build package
run: hatch build
# Security recommends we should pin deps. Should we pin the workflow version?
Copy link
Member

@agriyakhetarpal agriyakhetarpal Feb 27, 2025

Choose a reason for hiding this comment

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

Yes, please. I'll recommend that all GitHub Actions—whether by GitHub as an actor or external ones available on the marketplace—should be pinned to their commit hashes, at least for a workflow concerning a release. There is a case to be made about how it makes things a bit more challenging for new contributors/packagers, but I think supply-chain security shouldn't be at the end of a compromise.

There are tools such as gha-update which can replace them with pins, that we can recommend elsewhere (not in this PR, though, of course). Once this is done, I think it's just a matter of letting Dependabot (if configured) take over, as it can handle both the upgrade and the inline version comment in its automated PRs.

Copy link
Member Author

Choose a reason for hiding this comment

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

great. So, looking at the action here

Ofek suggests that too - we'd use this - this hash is almost the most recent but the most recent is just a readme update.

  • name: Install Hatch
    uses: pypa/hatch@a3c83ab

    But now we'd have to update that hash manually? How often should that update happen?

We should do that as part of this repo's maintenance, but also, we'll want to tell users to update this periodically, right?

Copy link
Member

Choose a reason for hiding this comment

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

great. So, looking at the action here

Ofek suggests that too - we'd use this - this hash is almost the most recent but the most recent is just a readme update.

  • name: Install Hatch
    uses: pypa/hatch@a3c83ab
    But now we'd have to update that hash manually? How often should that update happen?

We should do that as part of this repo's maintenance, but also, we'll want to tell users to update this periodically, right?

Updating it weekly for our maintenance could be a good cadence; what do you think? It would depend on the amount of activity we have on this template.

If we were to ask our users to enable Dependabot in the GitHub settings and inherit the same settings, they should also get the same updates. However, I'm not sure whether it's too much to ask for beginners (😕).

As long as it is pinned for a start, we can proceed with a small guide on how to keep this workflow maintained, where we can describe this more (or link to an external guide if that's alright and vetted by us?).

Copy link
Member Author

Choose a reason for hiding this comment

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

@agriyakhetarpal this is awesome. We, I think, have Depdendabot set up in the org, I think, but I didn't configure it. This is a basic question but would it help update things like this version? IE could we use it in this repo?

My gut tells me we won't have the bandwidth to perform weekly updates here unless someone wants to take that one! But perhaps monthly or quarterly would work. I am not sure what is best, however and would love suggestions.

also if you were interested in helping us maintain here, that would be awesome (only if you have bandwidth!)

Copy link
Member

Choose a reason for hiding this comment

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

We, I think, have Depdendabot set up in the org, I think, but I didn't configure it. This is a basic question but would it help update things like this version? IE could we use it in this repo?

Oh, I notice that here are a few moving parts, here. As this file is not a workflow of its own but a template that will be generated and moved into .github/workflows/, I am not sure if Dependabot will be able to operate on the template file as well, in addition to the workflow file. It does have a directory: setting, which I think we should try out: https://docs.github.com/en/code-security/dependabot/working-with-dependabot/dependabot-options-reference#directories-or-directory--

That means that we have two possible scenarios:

  • the GitHub Actions dependencies in this file get outdated and are not kept up to date: assuming we also ship a Dependabot configuration file with our template that will be copied (and we instruct users on how to use Dependabot), the generated workflow file will receive updates. This should be good for users, as they receive updates. However, we, as the ones shipping the template, would need to find a method to "mirror" the updates from our workflow file to the template file.
  • the GitHub Actions dependencies in this file are also updated in addition to our own workflows (that would be great!)

The first one is surely not ideal, so we should explore if Dependabot will choose to be the star here or not 😉

My gut tells me we won't have the bandwidth to perform weekly updates here unless someone wants to take that one! But perhaps monthly or quarterly would work. I am not sure what is best, however and would love suggestions.

I agree with you. Monthly updates would be nicer – and users can always bump it to daily, or weekly, and so on, based on their bandwidth.

also if you were interested in helping us maintain here, that would be awesome (only if you have bandwidth!)

I'd love to! I've also helped out with the development and maintenance of especially other copier templates, such as https://github.com/pybamm-team/pybamm-cookie – where my experience should be transferable enough for me to help out. I do have limited bandwidth, however and can't say I can work full-time on this, but I would be open to lend a hand with more reviews and occasional updates anytime :D

Copy link
Member Author

Choose a reason for hiding this comment

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

Ok wonderful!! @agriyakhetarpal i'm going to create an issue for thiw topic specifically as it's beyon the scope of this pr and merging this would be nice!! BUT it's an important topic. So let's move your comment above to an issue.

Also i'd love to add you to our packaging council team here at pyOpenSci which will give ou more superpowers in our repos!! I"ll do that now. So happy to have you here and also happy that @Midnighter is able to help me undstand some of the technical points and updates that you have so carefully pointed out and fixed!! thank you both!

Comment on lines 53 to 54
# Modify the repo name below to be your project's repo name.
if: github.repository_owner == 'pyopensci'
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
# Modify the repo name below to be your project's repo name.
if: github.repository_owner == 'pyopensci'
# Modify the repo name below to be your project's repo name.
if: github.repository == 'pyopensci/pyos-package-template'

How would you feel about a more stringent check here, like this? The idea is to make users more careful (and it's possible that a fork of the repository within one's organisation can trigger this workflow otherwise).

Comment on lines 14 to 16
# Environment is encouraged for increased security
environment: build
Copy link
Member

Choose a reason for hiding this comment

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

This is a new one for me, so I'm curious. Could you please share how it works?

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh! @agriyakhetarpal environments allow you to setup a trusted connection with pypi. This is the build environment, so we don't need to worry too much about security here in terms of PYPI. so anyone can run the build step in theory. but by having a publish environment, we can control who can trigger that step of the build. (if that is what you're asking) .

here is a bit more about this

https://docs.pypi.org/trusted-publishers/using-a-publisher/

Copy link
Member

Choose a reason for hiding this comment

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

Oh, I'm aware of trusted publishing and environments, thanks! My question was more around the need for this build environment, as it seems to be redundant. Most release workflows can get by with just one pypi (or publish, or any other similar name) environment, omitting the need for an environment for the build step. Does including two environments, one for building and one for publishing, have security provisions? Moreover, I imagine that the users would also have questions around why they need (and we recommend) to set up two environments in their repository's settings, when it is only the publishing one that connects to PyPI's OIDC publishing functionalities.

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh gosh my apologies. i suspected I was telling you something you already knew. 🙈

This is a great point. I don't know the answer to your question!! But i suspect this is ME introducing complexity.

i just checked the tutorials and there is a build step but not an additional environment. Shall we remove this environment as you are correct it's not required. we need the job but not an environment AFAIK .

Copy link
Member

Choose a reason for hiding this comment

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

Oh gosh my apologies. i suspected I was telling you something you already knew. 🙈

No worries at all! 😄

This is a great point. I don't know the answer to your question!! But i suspect this is ME introducing complexity.

i just checked the tutorials and there is a build step but not an additional environment. Shall we remove this environment as you are correct it's not required. we need the job but not an environment AFAIK .

Thank you for dropping it!

@lwasser
Copy link
Member Author

lwasser commented Feb 27, 2025

Ok i've made changes and seemingly have broken CI. I wondered if someone can help me understand how to test this locally. i tried:

copier copy . _law_tests to copy the template from my local dir with changes. (so it's "dirty" tecnnically". Do i have to build something first perhaps?

@lwasser
Copy link
Member Author

lwasser commented Feb 27, 2025

@all-contributors please add @agriyakhetarpal for review

Copy link
Contributor

@lwasser

I've put up a pull request to add @agriyakhetarpal! 🎉

@Midnighter
Copy link
Contributor

Ok i've made changes and seemingly have broken CI. I wondered if someone can help me understand how to test this locally. i tried:

copier copy . _law_tests to copy the template from my local dir with changes. (so it's "dirty" tecnnically". Do i have to build something first perhaps?

Copier by default applies the template from the last tag rather than the local version. A design choice I'm not super happy with either. You will need to use the -r option with your branch name so it uses your last commit instead.

@lwasser
Copy link
Member Author

lwasser commented Feb 27, 2025

Ok i've made changes and seemingly have broken CI. I wondered if someone can help me understand how to test this locally. i tried:
copier copy . _law_tests to copy the template from my local dir with changes. (So it's "dirty" technically). Do i have to build something first perhaps?

Copier by default applies the template from the last tag rather than the local version. A design choice I'm not super happy with either. You will need to use the -r option with your branch name so it uses your last commit instead.

This makes sense. Thank you, @Midnighter !!!

@lwasser
Copy link
Member Author

lwasser commented Feb 28, 2025

well it turns out #77 fixes this pr too. I am not sure why CI was passing before 🤷🏻‍♀️ but the issue was pydoclint can't run without knowing where to run.

Co-authored-by: Agriya Khetarpal <[email protected]>
Copy link
Member

@agriyakhetarpal agriyakhetarpal left a comment

Choose a reason for hiding this comment

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

Hi @lwasser, thank you! I really appreciate the warmth in your responses while addressing my review comments pyOS favicon

I'm happy to approve this PR in principle, it being a valuable step forward – even though there are a few pieces of unresolved conversations at the moment.

Comment on lines 14 to 16
# Environment is encouraged for increased security
environment: build
Copy link
Member

Choose a reason for hiding this comment

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

Oh gosh my apologies. i suspected I was telling you something you already knew. 🙈

No worries at all! 😄

This is a great point. I don't know the answer to your question!! But i suspect this is ME introducing complexity.

i just checked the tutorials and there is a build step but not an additional environment. Shall we remove this environment as you are correct it's not required. we need the job but not an environment AFAIK .

Thank you for dropping it!


- name: Build package
run: hatch build
# Security recommends we should pin deps. Should we pin the workflow version?
Copy link
Member

Choose a reason for hiding this comment

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

We, I think, have Depdendabot set up in the org, I think, but I didn't configure it. This is a basic question but would it help update things like this version? IE could we use it in this repo?

Oh, I notice that here are a few moving parts, here. As this file is not a workflow of its own but a template that will be generated and moved into .github/workflows/, I am not sure if Dependabot will be able to operate on the template file as well, in addition to the workflow file. It does have a directory: setting, which I think we should try out: https://docs.github.com/en/code-security/dependabot/working-with-dependabot/dependabot-options-reference#directories-or-directory--

That means that we have two possible scenarios:

  • the GitHub Actions dependencies in this file get outdated and are not kept up to date: assuming we also ship a Dependabot configuration file with our template that will be copied (and we instruct users on how to use Dependabot), the generated workflow file will receive updates. This should be good for users, as they receive updates. However, we, as the ones shipping the template, would need to find a method to "mirror" the updates from our workflow file to the template file.
  • the GitHub Actions dependencies in this file are also updated in addition to our own workflows (that would be great!)

The first one is surely not ideal, so we should explore if Dependabot will choose to be the star here or not 😉

My gut tells me we won't have the bandwidth to perform weekly updates here unless someone wants to take that one! But perhaps monthly or quarterly would work. I am not sure what is best, however and would love suggestions.

I agree with you. Monthly updates would be nicer – and users can always bump it to daily, or weekly, and so on, based on their bandwidth.

also if you were interested in helping us maintain here, that would be awesome (only if you have bandwidth!)

I'd love to! I've also helped out with the development and maintenance of especially other copier templates, such as https://github.com/pybamm-team/pybamm-cookie – where my experience should be transferable enough for me to help out. I do have limited bandwidth, however and can't say I can work full-time on this, but I would be open to lend a hand with more reviews and occasional updates anytime :D

Copy link
Contributor

@Midnighter Midnighter left a comment

Choose a reason for hiding this comment

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

I left some more minor comments, but don't want to stand in the way of what is generally a great improvement 🙂.

lwasser and others added 2 commits March 5, 2025 11:14
@lwasser
Copy link
Member Author

lwasser commented Mar 5, 2025

Ok friends!!

✅ i've got two checks of approval here so I think we can merge! But let's let ci run after I merged the last inline changes suggested!
@agriyakhetarpal I've integrated ALL of your changes and opened an issue about the dependabot. I've also invited you to our org and to the packaging team. This should give you more superpowers to help with all things pacakaging!

I'll go ahead and merge this once CI finishes (or someone else can!). Then we can decide what's next. I think documentation is likely going to be an important focus in the future!

@lwasser lwasser merged commit 4c650af into pyOpenSci:main Mar 5, 2025
6 checks passed
@lwasser lwasser deleted the fix-actions branch March 5, 2025 21:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

request: release workflow on GitHub and follow PyPA and PyPI security recommendations
4 participants