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

Usage with multiple-subject attestations #89

Open
AA-Turner opened this issue Feb 17, 2025 · 4 comments
Open

Usage with multiple-subject attestations #89

AA-Turner opened this issue Feb 17, 2025 · 4 comments

Comments

@AA-Turner
Copy link
Contributor

GitHub's actions/attest changed in version 2 to produce a single Sigstore attestation for all artefacts, instead of the previous behaviour (one attestation per artefact). I've tried upgrading to this, but I hit the error stating that each statement must have exactly one subject. Is it possible to work around this, or should this be fixed in actions/attest?

https://github.com/trailofbits/pypi-attestations/blob/v0.0.21/src/pypi_attestations/_impl.py#L274-L275

I've opened a similar issue on the action repo: actions/attest#213

A

@woodruffw
Copy link
Member

Hi @AA-Turner, sorry for the delayed response here!

Yeah, this is a known problem -- we intentionally standardized PEP 740 around a single-subject assumption, since that most closely aligns with how PyPI and other index machinery works (i.e. all operations happen on single release files, there's no "batch" uploading).

We could relax the requirement here (and within PEP 740, PyPI, etc.), but I'm wary about doing so because it subtly changes the verification model: instead of PyPI being able to fully assert that the subject of an attestation exactly matches the expected release file, the model becomes "1-of-N subjects match." This in turn enables a kind of confused deputy attack:

  1. Publisher github.com/foo/bar is trusted to attest for pypi:foo
  2. Publisher github.com/joe/schmoe is trusted to attest for pypi:pyschmoe
  3. github.com/foo/bar attests for pypi:foo @ sha256:abcd and for pypi:pyschmoe @ sha256:defg, the latter of which is inauthentic
  4. PyPI accepts the attestation from github.com/foo/bar because it contains a valid attestation for pypi:foo and ignores the invalid one for pypi:pyschmoe
  5. Subsequent consumers of the provenance API responses conflate valid and invalid attestations for pypi:pyschmoe, especially in caching scenarios where all index-verified attestations are collected and reduced to just "trusted" subjects.

To work around this, PyPI could in theory allow multiple subjects, but only under the same project namespace. This complicates the index-side verification slightly (since we'd need to parse all subjects, not just reject non-matching ones), but it might be worth it.

However, to take a step back: you're hitting this because you're using actions/attest, but I think you could replace that with pypi-attestations sign dist/* (or the Python APIs) instead. That command will always generate single-subject attestations, since it matches the PEP's specified behavior. I'm curious if this would be an acceptable solution for you 🙂

@AA-Turner
Copy link
Contributor Author

Hi @AA-Turner, sorry for the delayed response here!

No worries!

Yeah, this is a known problem -- we intentionally standardized PEP 740 around a single-subject assumption, since that most closely aligns with how PyPI and other index machinery works (i.e. all operations happen on single release files, there's no "batch" uploading).

To work around this, PyPI could in theory allow multiple subjects, but only under the same project namespace. This complicates the index-side verification slightly (since we'd need to parse all subjects, not just reject non-matching ones), but it might be worth it.

Right, I'd only expect to be able to upload multiple subjects for projects I control, and probably only multiple subjects for the same version release of the same project.

However, to take a step back: you're hitting this because you're using actions/attest, but I think you could replace that with pypi-attestations sign dist/* (or the Python APIs) instead.

My original attempt (see #55) used the CLI, but you told me not to :) (more accurately, that the Python API in this project is what we should rely on).

I like using the actions/attest action as it also uploads attentions to GitHub (though not PEP 740). What I'm gathering though is that this is a request on the GH side to restore support for creating single-subject attenuations in that action, especially given the PEP is standardised around them.

A

@woodruffw
Copy link
Member

My original attempt (see #55) used the CLI, but you told me not to :) (more accurately, that the Python API in this project is what we should rely on).

Yeah, sorry for the mixed messages here 😅 -- I'm trying to encourage people to use the API if at all possible, but I can understand if/why that's annoying in a CI/CD context.

I like using the actions/attest action as it also uploads attentions to GitHub (though not PEP 740). What I'm gathering though is that this is a request on the GH side to restore support for creating single-subject attenuations in that action, especially given the PEP is standardised around them.

Makes sense! Yeah, I would personally love it if actions/attest retained a "single-subject" mode for this kind of use case, perhaps as an opt-in setting.

On a related note, I think the APIs that GH uses to upload attestations are public, and I've been meaning to look into using those. If they are, it wouldn't be hard for me/my team to build a trailofbits/pypi-attest or similar action that uses pypi-attestations internally and also does the GH-side attestation upload correctly 🙂

@AA-Turner
Copy link
Contributor Author

I've updated the other thread in actions/attest#213, hopefully we get a response on the GH side.

Yeah, sorry for the mixed messages here 😅 -- I'm trying to encourage people to use the API if at all possible, but I can understand if/why that's annoying in a CI/CD context.

Don't worry! I wrote convert_attestations.py which I've now used in a couple of projects -- as I said in #55, I appreciate most users will probably use the pypa GitHub Action, and this is a more esoteric case.

On a related note, I think the APIs that GH uses to upload attestations are public, and I've been meaning to look into using those.

The README of the action directs to the @actions/attest JS package, which just seems to use the GH REST API internally POST .../attestations

A

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

No branches or pull requests

2 participants