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

Add SLSA provenance to release workflow #847

Closed
wants to merge 6 commits into from
Closed

Conversation

pnacht
Copy link
Contributor

@pnacht pnacht commented Nov 29, 2022

Closes #844.

As per the linked issue, this PR adds automatic SLSA provenance generation to the release workflow (main.yml). SLSA provenance allows maintainers and consumers to guarantee that the jars came from the expected, trusted source. See the linked issue for more information.

Currently the provenance attestation is only "attached" to the workflow (or added to GitHub releases, if the project used them). Given that Maven allows for arbitrary files in their releases, it would be best if the attestation could also be added to the release. However, I must admit my ignorance as to how precisely to do that via GitHub Actions.

You'll notice the provenance is created in a separate job from the rest of the workflow. This is for security purposes, to ensure the provenance generation is isolated and secure against external interference. If there's interest, I could submit another PR to split the build job into build, deploy, and codecov jobs. This would ensure that things such as credentials cannot leak to other steps (see GitHub's docs on risks of compromised runners).

Signed-off-by: Pedro Kaj Kjellerup Nacht <pnacht@google.com>
Signed-off-by: Pedro Kaj Kjellerup Nacht <pnacht@google.com>
Signed-off-by: Pedro Kaj Kjellerup Nacht <pnacht@google.com>
Signed-off-by: Pedro Kaj Kjellerup Nacht <pnacht@google.com>
Signed-off-by: Pedro Kaj Kjellerup Nacht <pnacht@google.com>
Signed-off-by: Pedro Kaj Kjellerup Nacht <pnacht@google.com>
@@ -26,18 +26,22 @@ jobs:
fail-fast: false
matrix:
# As of Jackson 2.14 got Java 8 baseline so can build on later JDKs too
java_version: ['8', '11', '17']
os: ['ubuntu-20.04']
java_version: ["8", "11", "17"]
Copy link
Member

Choose a reason for hiding this comment

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

Any particular reason for this change? (adds noise)

Not a big deal, just curious if there's a reason for preference.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh sorry, that was my linter! You'll notice the last commit was fixing some whitespace changes it'd also done, but I missed this change, my apologies. I can undo it, if you prefer.

if: |
github.event_name != 'pull_request' &&
matrix.java_version == '8' &&
endsWith(steps.projectVersion.outputs.version, '-SNAPSHOT')
Copy link
Member

Choose a reason for hiding this comment

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

This would only calculate hashes for SNAPSHOT builds, not for actual releases?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My understanding is that this specific workflow (main.yml) only deploys SNAPSHOT builds (per the if conditional in the Deploy snapshot step above), and I therefore assumed there was another workflow or process (not necessarily via GitHub) for actual releases.

I meant for this PR to be a demonstration of how SLSA can be incorporated into your automated workflow, so I kept this workflow's logic of only deploying SNAPSHOTs and only generated provenance for the deployed SNAPSHOT.

If there's another automated workflow I can look at for actual releases, I'd be happy to make similar modifications there. Or, if releases are made from your local machine, I'd be happy to help migrate that process onto an automated workflow as well.

Copy link
Member

Choose a reason for hiding this comment

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

Ah ok.

So here we might have a challenge: releases are not triggered by CI -- I trigger them from my work station using Maven release plug-in (so second option).
But while I know how releases are often triggered via CI (from tagging), I haven't quite found those to my liking, at least the way most corporations do it: they tend to geared towards patch-increase only cases, for (web) applications where there is little semantic information in version numbers.

Work involved would also be quite substantial as well considering none of Jackson repos uses CI releases at this point.
And I do need to be able to release versions from multiple branches.

But longer term I can see why use of CI would be preferable to local work station -- for multiple reasons. So I am not philosophically against it at all. Just more concerned about practical path there.

One thing that might help would be finding good CI workflow to consider adopting: something used for library/framework use case where semantic versioning is used (or rather, where version number increments need to be somewhat more flexible; including occasional release of micro-patches).

I haven't really followed how other OSS projects deal with this so not sure where to look. I guess I could ask on Tidelift OSS slack channels; Joda project might be a good candidate to consider.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Let me know if I'm missing something, but GitHub workflows should be able to handle different branches and be indifferent to tag naming conventions.

We could likely create a workflow very similar to this one but that's triggered:

  • manually (on: workflow_dispatch). You'd pass the branch/tag/commit to use by hand.
  • whenever a new GitHub Release is created (on: release). So you define the branch/tag/commit from which to run. For an example (including SLSA provenance generation), see the release workflow for the sigstore-python library.

You can also use the gh CLI or simply curl to perform these actions remotely.

I'm not an expert on releasing on Maven, so I'm unsure if there are additional steps required for actual releases.

(Let me know if you'd rather migrate this conversation somewhere more appropriate)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

And I do need to be able to release versions from multiple branches.

It just occurred to me you might've meant you need to be able to release from multiple repos (jackson & jackson-core, for example). In this case, we could write a shell script to make the gh/curl calls for all the repos at once.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry for the delay in replying, I've been getting more familiar with the Maven release plugin.

As I've come to understand it from the docs, the magic really happens in the prepare stage. My understanding is that prepare:

  • Bumps everything from x-SNAPSHOT to the new release version
  • Commits the changed POMs
  • Creates a tag for the new version
  • Bumps everything to the next y-SNAPSHOT
  • Commits the changed POMs again

Meanwhile, perform simply builds and deploys. From a security standpoint, however, the most important step to have in CI is actually perform.

I've therefore had the idea of splitting the workflow into two parts: we can write a shell script you run on your local machine that runs :clean :prepare and pushes everything to GitHub (including the tag created by prepare). We can then have a GitHub workflow that triggers on new tags (excluding *-rc release-candidate tags) and simply runs the final :perform.

Your release process would therefore be almost unchanged. Instead of calling mvn release:clean release:prepare release:perform, you'd call release.sh, which would give you the same behavior as mvn release:clean release:prepare and then automatically trigger the CI mvn release:perform by pushing the new commits and tag.

Would you be interested in exploring this?

Copy link
Member

Choose a reason for hiding this comment

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

Hi @pnacht ! Apologies for slow response here. But: yes, I think that sounds like a reasonable compromise and I would be interested.
I think we could play with this for core components (jackson-core, jackson-databind, jackson-annotations).

One quick note: I will be now off for vacation until January 4th 2023 so let's sync up early next year.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hey @cowtowncoder, hope you had a good vacation! I've started sketching out the script to replace mvn release:clean release:prepare and should have the workflow that'll do the final mvn release:perform end of next week. I'll submit those as a separate PR, is that alright?

Copy link
Member

Choose a reason for hiding this comment

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

@pnacht That makes sense to me (separate PR)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sorry for the delay! But I've submitted the PR as discussed above: #896.

@cowtowncoder
Copy link
Member

@pnacht just to make sure: can this be closed as I am to merge #896?

@pnacht
Copy link
Contributor Author

pnacht commented Feb 14, 2023

Yep!

@pnacht pnacht closed this Feb 14, 2023
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.

None yet

2 participants