Skip to content

fix(bitbucket): never crash on a null field in a Bitbucket reply - #1286

Open
AlexKantor87 wants to merge 10 commits into
mainfrom
claude/1283-bitbucket
Open

AlexKantor87 wants to merge 10 commits into
mainfrom
claude/1283-bitbucket

Conversation

@AlexKantor87

Copy link
Copy Markdown
Contributor

Part of #1283. Builds on #1285 (test helpers), so this PR's base is that branch. It moves to main once #1285 merges.

kosli attest pullrequest bitbucket and kosli assert pullrequest bitbucket crashed 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

  • Safe readers. str, obj, boolean and objects read a field and give an empty value when it's missing, null or a different type. They replace every unchecked read in bitbucket.go, on both the V1 path (assert) and the V2 path (attest).
  • Unreadable list entries still fail. A null item in values or participants returns an error that names the list and index. Skipping it could hide a "changes requested" review.
  • Empty timestamps are 0, not an error.
  • Clear errors where we can't carry on. A PR with no links.self.href (the next request's URL) or no id (needed to fetch commits) now returns a readable error.

Tests

odd_replies_test.go sends 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 two cases above. Before the fix, 62 cases crashed. Now all 340 pass.

Not changed

Full CLI suite against a local server: 3,989 tests passed.

🤖 Generated with Claude Code

AlexKantor87 and others added 2 commits October 21, 2026 17:45
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>
@github-actions github-actions Bot added go Pull requests that update go code fix labels Oct 21, 2026
@claude

claude Bot commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Claude finished @AlexKantor87's task in 1m 11s —— View job


Follow-up review complete

  • Gather context: diff between BEFORE/AFTER, prior review comments
  • Evaluate status of each previous finding touched by new commits
  • Close resolved inline threads (all three were already marked resolved on GitHub)
  • Flag any new bugs/regressions in the changed lines
  • Post summary comment

Summary: The new commits (9a1287f8, 507500b3) only merge origin/main (which already includes #1291) into this branch. The only line-level diff between BEFORE (5b6d96b) and AFTER (507500b) is .github/dependabot.yml's schedule tweak — identical to #1291, and out of scope here per the PR author's note. No bitbucket-related code was touched by this push.

None of the three previous findings' locations were touched by the new commits:

  • bitbucket.go:338 (infinite-loop risk) — resolved by 747773f2 (confirmed defaultMaxPages cap present).
  • bitbucket.go:345 (empty date → epoch 0) — not addressed, deliberately deferred to Decide which PR evidence fields are required for each provider #1284.
  • odd_replies_test.go:313 (regexp-per-subtest nit) — not addressed, declined by author as a style preference.

No new bugs or regressions found in the changed lines. Full details posted as a PR comment.

Comment thread internal/bitbucket/bitbucket.go
Comment thread internal/bitbucket/bitbucket.go
Comment thread internal/bitbucket/odd_replies_test.go
Base automatically changed from claude/odd-reply-helper to main October 22, 2026 08:29
AlexKantor87 and others added 7 commits October 22, 2026 10:09
# 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>
@AlexKantor87

Copy link
Copy Markdown
Contributor Author

This branch now includes #1291's branch, so the Go 1.26.10 change clears the Snyk check here. That's why go.mod, Dockerfile, .github/dependabot.yml and internal/version/toolchain_test.go show in this diff. They're identical to #1291 and drop out of the diff once it merges. Please review those files on #1291, not here.

no search: answers no review finding; it brings in #1291's reviewed files unchanged (git diff origin/claude/go-1.26.10 HEAD on those four files is empty).

…283-bitbucket

# Conflicts:
#	.github/dependabot.yml
@claude

claude Bot commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

Follow-up review: BEFORE 5b6d96b..AFTER 507500b

The new commits (9a1287f8, 507500b3) only merge in origin/main, which already includes #1291. The only line-level change in git diff 5b6d96b..507500b is .github/dependabot.yml's schedule tweak — identical to #1291 and out of scope here per the PR description's note to review that on #1291 instead. No bitbucket-related files were touched by this push.

Status of previous findings (none of these locations were touched by the new commits, so this is a re-check, not a re-review):

  • bitbucket.go:338 (possible infinite loop if values is missing/non-list) — resolved, fixed by 747773f2 (defaultMaxPages cap, confirmed present in the code). Thread already resolved.
  • bitbucket.go:345 (empty date → timestamp: 0) — not addressed, by design: deferred to Decide which PR evidence fields are required for each provider #1284 per author reply. Thread already resolved (acknowledged, no code change expected here).
  • odd_replies_test.go:313 (regexp compiled per subtest) — not addressed, declined as a style nit per author reply. Thread already resolved.

New issues in the changed lines: none. The only diff is the dependabot schedule change, which is trivial and already covered by #1291.

No new inline comments needed.

View job run

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fix go Pull requests that update go code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant