Repository navigation
fix(bitbucket): never crash on a null field in a Bitbucket reply - #1286
Conversation
Part of #1283. Provider tests use these to send their evidence code a realistic reply once per field with that field made null, or a list emptied, and to name the outcome: ok, error or panic, plus which evidence fields came back changed or missing.
Every field was read with an unchecked type assertion, so a null or missing value (an approver with no state, a PR with no author) panicked with a Go stack trace. Fields are now read through one set of safe getters that give the zero value, and empty timestamps parse to 0. A null item in a list we read (values, participants) is an error naming the list and index, not a silent skip. The only null fields that still fail are the PR's links.self.href and id, which the next request needs. The test nulls each value of realistic replies in turn through both PREvidenceForCommitV1 (assert) and V2 (attest) and asserts the rule. Part of #1283 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Claude finished @AlexKantor87's task in 1m 33s —— View job Follow-up review: BEFORE
|
# Conflicts: # internal/testHelpers/oddReplies.go # internal/testHelpers/oddReplies_test.go
Snyk fails every branch on CVE-2026-111943, a high-severity flaw in Go's crypto/x509 fixed in 1.26.10; go.mod declared 1.26.7. The Dockerfile built from golang:1.26-alpine3.23, so each build could pull a different toolchain. It now names golang:1.26.10-alpine3.23 by digest. Dependabot can't update a FROM built from ARGs, so the line is literal, and a docker ecosystem entry (golang only) keeps the digest current.
… advance An approved participant with no user or display_name was counted as an approval by nobody, which records approval evidence that fails open. It is now an entry we can't read and errors, naming participants[i], for both assert (V1) and attest (V2). Commit paging followed next even when it pointed at the page just fetched, so such a reply looped forever. It now errors instead, matching the gitlab and github "did not advance" guards. Part of #1283 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dependabot bumps the pinned golang image on its own, and none of the gomod updates touch go.mod's go directive. Snyk reads go.mod, so an image-only bump would leave the next Go stdlib CVE flagged even though the image is fixed. The test makes that bump red until go.mod moves too.
…in reviews The previous commit made an approval with no user or display_name an error. A deleted account is a legal reply with no identity, so any pull request it ever approved could never be attested again, with no workaround. Now an approval with no identity is left out of the approvers, so it never counts as an approval, and is kept in the reviews with an empty name and its state, so the record still shows an unknown account reviewed. One helper, approvedBy, decides it for V1 and V2. Part of #1283 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The earlier guard only stopped a next link that was the page just fetched. Two pages pointing at each other still looped forever, and the earlier commit was wrong to say it matched GitLab: GitLab also caps the number of pages. Bitbucket's next is an opaque URL, so there is no page number to check for going up; a cap is the guard that ends every cycle. Commit paging now stops with an error after defaultMaxPages (1000) pages. The same-page check is dropped: the cap covers it. Part of #1283 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
This branch now includes #1291's branch, so the Go 1.26.10 change clears the Snyk check here. That's why no search: answers no review finding; it brings in #1291's reviewed files unchanged ( |
…283-bitbucket # Conflicts: # .github/dependabot.yml
Follow-up review: BEFORE
|
b49f8b9 kept a nameless approval in Reviews with state APPROVED. Policies read Reviews, so one that counts approvals there would count an approval by nobody: the same fail-open the approvers fix closed. This restores main's rule in bitbucketReviews exactly: a review with no name is kept only when it requests changes, since dropping that would read as none given. Nameless approvals stay out of Approvers. Never an error. Part of #1283 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The nameless-participant check only looked at nameless entries, so a bug that put a placeholder name on an approver, or dropped another person's named review, still passed. Compare both lists with the evidence for the same replies with the name present: only that person's entries may change. Part of #1283 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Follow-up review: BEFORE
|
|
An error for an unreadable list entry named only the list and index, such as values[0], so a user couldn't tell which commit or pull request it was about. It now says what the list belongs to: the commit for its pull requests, or the pull request for its participants and commits. Part of #1283 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A commit page entry with a null hash was recorded with an empty SHA. A commit with no SHA can't be attested, so it now returns an error naming the commit's index and the pull request. Part of #1283 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A commit's index restarted at 0 on each page of commits, so the no-hash error could name the same index for two different commits. It now counts across pages, and an unreadable entry on a commit page names its page. An unreadable participant's error named the pull request by its web link, which is empty when the reply has no links.html. It now uses the API URL, which every request needs. Part of #1283 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks @mbevc1. 1. Commit with no 2. Approver and review disagreeing. Added to #1284. The same thing happens on Azure (a vote of 5 is Same sweep, after your #1287 nit: errors for an unreadable list entry now name their commit or pull request, plus the page for commit pages (e20143f). search: grep -nE 'objects(|has no hash' internal/bitbucket/bitbucket.go verified: sed -n '349,352p' internal/bitbucket/bitbucket.go mutation: drop the hash check -> TestOddReplies_CommitWithNoHashFails red (2 cases) |
Part of #1283.
kosli attest pullrequest bitbucketandkosli assert pullrequest bitbucketcrashed when Bitbucket sent a field as null where the code expected a value. A crash prints a Go stack trace that doesn't say which field caused it. For now we treat every field as optional (#1284 will decide which fields are required).What changed
str,obj,booleanandobjectsread a field and give an empty value when it's missing, null or a different type. They replace every unchecked read inbitbucket.go, on both the V1 path (assert) and the V2 path (attest).valuesorparticipantsreturns an error that names the list and index. Skipping it could hide a "changes requested" review.links.self.href(the next request's URL) or noid(needed to fetch commits) returns a readable error. So does a commit with nohash. An unreadable list entry's error names its commit or PR.mainit loops forever if Bitbucket'snextlink points back to a page already read. It now stops after 1,000 pages with an error.reviewsonly a change request is kept, as onmain, because dropping it would read as no objection.Tests
odd_replies_test.gosends realistic replies through V1 and V2 once per field, with that field made null. It checks there's never a crash, and never an error except the cases above. When a participant has no name, it checks that only that person's entries change. Before the fix, 62 cases crashed.Full CLI suite against a local server: 3,997 tests passed.
🤖 Generated with Claude Code