Idea: gitsign attest
Description
~~This is an idea I've had rattling in my mind for awhile that I figured I'd finally write down.~~ Not an original idea! see https://github.com/sigstore/cosign/issues/865 for initial discussion.
It would be cool to add attestation support to Gitsign similar to cosign attest! i.e.
$ gitsign attest --predicate=<file> <revision>
$ gitsign verify-attestation <revision>
Primary use case would be to attach attestation information about the source / code review to the commit itself - who reviewed the change, what tests ran against it, etc (maybe also SBOMs, but unclear why you'd want that in an attestation rather than in the repo itself).
Predicate schema TBD. There are some ideas in https://github.com/in-toto/attestation/blob/77e31a3e4456de0594f0faf0ee5a1e65cfaf63d6/README.md#custom-type-examples that we can use to get started and would be a good place to work with the broader SLSA community to canonicalize.
We can generate the attestation using the same DSSE process we're using for cosign attest.
We can store the attestation in a way similar to a git note, though likely under a different ref refs/attestations. We probably can't use notes directly because IIUC notes expect 1 note per commit, where as we'll likely have many attestations per commit. It'll likely look something like:
refs/attestations/commits
`- <tree sha>
|- <commit 1>
|- attestation1.json
`- attestation2.json
`- <commit 2>
`- attestation1.json
Things to work out / double check the behavior of:
- How do multiple attestations work with
cosign attest? - How do we distinguish multiple attestations? (use the digest as the filename? user provided key?)
- Do we need a mechanism to delete an attestation?
- Standardize some common predicate formats.
- Should we have a way to identify predicate types? (i.e. code review vs tests)
- Is storing all attestations under the a single ref like
refs/attestations/commitsokay, or should we store attestations in a ref per commit? (i.e.refs/attestations/<target commit sha>). Probably worth looping in someone more familiar with git internals to advise here.- there might be some interesting ACL things source providers could do if we isolate per SHA (i.e. only let CI running at the commit modify attestations for the same commit)
- And probably more I'm not thinking of.
Let me know if you have any thoughts!
cc some people I know might be interested - @asraa @mattmoor
Definitely excited by the prospect here, and we can probably close https://github.com/sigstore/cosign/issues/865 in favor of this, so let me do that 😂
One of the nice things about git notes is that it shows up nicely in git log already (not sure how hard that is). One of the gotchas is that it isn't nicely merges as part of the standard PR flow.
That said, I do really like the parallels between git remotes and COSIGN_REPOSITORY in cosign for pushing attestations to others places, which allows differentiated write access between these things.
A ha! I thought there was a previous discussion about this - totally forgot it was in that cosign issue. Thanks for linking @mattmoor! 😅
Yeah what I'm suggesting here is inline with your git notes / git appraise idea, just in a different refspace. AFAIK there isn't a strict requirement that notes need to be in refs/notes, so if we wanted it to show up in git log we can (just need to set notes.displayRef).
Some things I'd be a little worried about -
- fully serialized attestations aren't going to be the most user friendly to read, so I'm not sure if we'd want them to just up in the git log output verbatim. We could always maintain a separate user-friendly, non-authoritative note that just references the real attestation objects to work around this though.
refs/attestations/<target commit sha>format isn't going to be compatible with git notes, but a note summary would also work around this.
One of the gotchas is that it isn't nicely merges as part of the standard PR flow.
Yeah this is annoying, but this is also intentional though - If we assume the merger to be malicious (either intentionally or by compromise), any modifications during the commit during submission should invalidate the attestation / signature.
We could do something like https://github.com/sigstore/cosign/issues/865#issuecomment-939350800 suggests and attach the attestation to the tree object rather than the commit (or the commit object with changed values like parent/committer removed), but I'm slightly worried this wouldn't be sufficient for all types of attestations. For CI attestations this might make sense because you care more about the file content rather than who made the change / what graph structure it had, but preserving commit data feels more important for code review attestations (e.g. approving an octopus merge is much different than approving a simple single commit, even if the end result led to the same tree SHA).
Related, I'm curious to explore what we could do at merge time with merge queues / on post-submit to reattach attestations to the merging commits (or even just generate new attestations). This might be a place where we can define rules on what commits we consider equivalent 🤔
Not a great multi-platform solution, but GitHub does have an API for getting PRs from commit SHAs: https://docs.github.com/en/rest/commits/commits#list-pull-requests-associated-with-a-commit
So you could use this to go from merged/rebased commit -> PR -> head SHA -> refs/attestations/<head sha>. From there you could attach a new attestation to the merged commit based on the original PR head's attestation(s).
This won't work for locally rebased changes. For that users would need to reattach any attestations and attest to them themselves. Some automation could be done here with post-rewrite hooks, but I think in most cases users would just push to a PR and let the CI re-attest to the commits as if they were new.
https://github.com/sigstore/gitsign/pull/195