fix(tools): bound Gitea read-back to this write; verify approve/reject state (#865)
All checks were successful
ci/woodpecker/pr/ci Pipeline was successful
All checks were successful
ci/woodpecker/pr/ci Pipeline was successful
Review remediation for two correctness holes in the #865 fix: BLOCKER 1 — issue-comment.sh read-back was body-only across all history: if `tea comment` silently no-opped (the #865 bug) while an identically bodied comment already existed from a prior run, the read-back matched the OLD comment and falsely reported success. Now record the pre-write maximum comment id as a boundary and require a comment with id > boundary AND exact body match; monotonic Gitea ids make id > boundary mean "created by this write". Fails closed otherwise. BLOCKER 2 — pr-review.sh approve/reject trusted tea's exit code for the review STATE (same never-trust-exit-zero defect class as #865). Removed the TODO deferral and added a real bounded read-back: record the max review id before `tea pr approve`/`reject`, then require a review with id > boundary, the expected state (APPROVED / REQUEST_CHANGES), and commit_id equal to the PR's current head. Fails closed if absent. Tests: extended test-pr-review-gitea-comment.sh to model and assert the new review-state read-back (guardrails preserved, assertions added). Added test-issue-comment-readback.sh proving the pre-existing-identical-body false positive now fails closed and a genuinely new comment verifies. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -4,11 +4,11 @@ These scripts provide host-aware GitHub and Gitea issue, pull-request, milestone
|
||||
|
||||
## Durable review provenance
|
||||
|
||||
A successful provider write command—or a wrapper message based only on that command's exit code—is **not** durable review provenance. Review comments count as durable provenance only after the wrapper reads the created provider record back and verifies that it belongs to the intended repository and pull request and contains the exact submitted body (or verifies the provider-returned record ID).
|
||||
A successful provider write command—or a wrapper message based only on that command's exit code—is **not** durable review provenance. Review comments, approvals, and change requests count as durable provenance only after the wrapper reads the created provider record back and verifies that it was created by _this_ write.
|
||||
|
||||
`pr-review.sh` therefore fails closed when a Gitea comment cannot be written, its created comment ID cannot be identified, or provider read-back does not match. It reports comment success only after that read-back verification passes.
|
||||
`pr-review.sh` therefore fails closed when a Gitea comment cannot be written, its created comment ID cannot be identified, or provider read-back does not match. It reports comment success only after that read-back verification passes. The `approve` and `request-changes` actions apply the same discipline to the review **state** itself: they record the maximum existing review id _before_ invoking `tea pr approve`/`reject`, then require a review whose id is strictly greater than that boundary, whose state matches the requested action (`APPROVED` / `REQUEST_CHANGES`), and whose reviewed commit equals the PR's current head. tea's exit code alone is never treated as evidence the review landed.
|
||||
|
||||
`issue-comment.sh` applies the same fail-closed read-back verification to issue comments: after posting via `tea comment`, it independently re-fetches the issue's comments via the Gitea REST API and confirms one matches the submitted body before reporting success.
|
||||
`issue-comment.sh` applies the same fail-closed, boundary-bounded read-back to issue comments: it records the maximum existing comment id _before_ posting via `tea comment`, then re-fetches the issue's comments via the Gitea REST API and requires a comment whose id is strictly greater than that boundary **and** whose body exactly matches what was submitted. Bounding the read-back by the pre-write id is essential — a body-only match across all history would falsely report success if `tea comment` silently no-ops (the #865 bug) while an identically-bodied comment already existed from a prior run. Gitea comment and review ids are monotonic, so `id > boundary` reliably means "created after this write began".
|
||||
|
||||
## `tea` invocation notes (Gitea)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user