-
Notifications
You must be signed in to change notification settings - Fork 8
fix(attest): always serialise commits in pull request attestations #1083
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
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| package gitlab | ||
|
|
||
| import ( | ||
| "github.com/kosli-dev/cli/internal/types" | ||
| ) | ||
|
|
||
| // FakeGitlabClient is an in-memory implementation of types.PRRetriever for | ||
| // testing. Seed MRsByCommit with the commits and merge request evidence you | ||
| // want returned. Set Err to simulate a network or API failure. | ||
| type FakeGitlabClient struct { | ||
| // MRsByCommit maps a commit SHA to the merge request evidence returned | ||
| // for that commit. | ||
| MRsByCommit map[string][]*types.PREvidence | ||
| // Err, if set, is returned by all calls regardless of commit. | ||
| Err error | ||
| } | ||
|
|
||
| func (f *FakeGitlabClient) ProviderAndLabel() (string, string) { | ||
| return "gitlab", "merge request" | ||
| } | ||
|
|
||
| // PREvidenceForCommitV2 mirrors the real client: a commit with no merge | ||
| // requests yields an empty result and no error, because GitLab's | ||
| // ListMergeRequestsByCommit returns an empty list rather than an error. | ||
| // | ||
| // The result is always non-nil. The real client builds its slice up front, and | ||
| // a nil slice would serialise as null, which the API rejects for pull_requests. | ||
| func (f *FakeGitlabClient) PREvidenceForCommitV2(commit string) ([]*types.PREvidence, error) { | ||
| if f.Err != nil { | ||
| return nil, f.Err | ||
| } | ||
| mrs := f.MRsByCommit[commit] | ||
| if mrs == nil { | ||
| return []*types.PREvidence{}, nil | ||
| } | ||
| return mrs, nil | ||
| } | ||
|
|
||
| // PREvidenceForCommitV1 mirrors the real client, which serves V1 from the same | ||
| // merge request lookup as V2. | ||
| func (f *FakeGitlabClient) PREvidenceForCommitV1(commit string) ([]*types.PREvidence, error) { | ||
| return f.PREvidenceForCommitV2(commit) | ||
| } | ||
|
|
||
| // PREvidenceForCommitHybrid mirrors the real client, which has no V1 fallback | ||
| // for GitLab and always serves V2. | ||
| func (f *FakeGitlabClient) PREvidenceForCommitHybrid(commit string) ([]*types.PREvidence, error) { | ||
| return f.PREvidenceForCommitV2(commit) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| package gitlab | ||
|
|
||
| import ( | ||
| "testing" | ||
|
|
||
| "github.com/kosli-dev/cli/internal/types" | ||
| "github.com/stretchr/testify/require" | ||
| ) | ||
|
|
||
| // The real client builds its result slice up front, so a commit with no merge | ||
| // requests yields an empty list rather than nil. The fake must match: a nil | ||
| // slice serialises as null, and the API rejects null for pull_requests. | ||
| func TestFakeGitlabClientReturnsEmptyNotNilForUnknownCommit(t *testing.T) { | ||
| client := &FakeGitlabClient{ | ||
| MRsByCommit: map[string][]*types.PREvidence{ | ||
| "known": {{URL: "https://gitlab.com/org/repo/-/merge_requests/1"}}, | ||
| // an explicitly seeded nil must be normalised too | ||
| "seeded-nil": nil, | ||
| }, | ||
| } | ||
|
|
||
| for _, retrieve := range []struct { | ||
| name string | ||
| call func(string) ([]*types.PREvidence, error) | ||
| }{ | ||
| {"V2", client.PREvidenceForCommitV2}, | ||
| {"V1", client.PREvidenceForCommitV1}, | ||
| {"Hybrid", client.PREvidenceForCommitHybrid}, | ||
| } { | ||
| for _, commit := range []string{"unknown", "seeded-nil"} { | ||
| t.Run(retrieve.name+"/"+commit, func(t *testing.T) { | ||
| mrs, err := retrieve.call(commit) | ||
| require.NoError(t, err) | ||
| require.NotNil(t, mrs, "must be an empty slice, not nil") | ||
| require.Empty(t, mrs) | ||
| }) | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| package types | ||
|
|
||
| import ( | ||
| "encoding/json" | ||
| "testing" | ||
|
|
||
| "github.com/stretchr/testify/require" | ||
| ) | ||
|
|
||
| // The API validates pull request attestations against FoundPullRequestV2, which | ||
| // requires "commits". Dropping the field when a provider returns no commits | ||
| // produces a payload that matches neither V1 nor V2 and is rejected (#1081). | ||
| func TestPREvidenceAlwaysSerialisesCommits(t *testing.T) { | ||
| for _, tc := range []struct { | ||
| name string | ||
| evidence PREvidence | ||
| want string | ||
| }{ | ||
| { | ||
| name: "empty commits serialise as an empty array", | ||
| evidence: PREvidence{Commits: []Commit{}}, | ||
| want: `[]`, | ||
| }, | ||
| { | ||
| name: "nil commits serialise as an empty array", | ||
| evidence: PREvidence{}, | ||
| want: `[]`, | ||
| }, | ||
| } { | ||
| t.Run(tc.name, func(t *testing.T) { | ||
| payload, err := json.Marshal(tc.evidence) | ||
| require.NoError(t, err) | ||
|
|
||
| var decoded map[string]json.RawMessage | ||
| require.NoError(t, json.Unmarshal(payload, &decoded)) | ||
|
|
||
| raw, present := decoded["commits"] | ||
| require.True(t, present, "commits must always be present in the payload") | ||
| require.JSONEq(t, tc.want, string(raw)) | ||
| }) | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.