b4a696a5e9
* fix(github): hide approve PR button on own PRs and reject self-approval server-side The frontend's existing self-author check failed open when the current GitHub user hadn't loaded yet — the PR panel didn't call useGitHubStatus, so the green Approve button flashed on every PR (including your own) during the brief window before /api/v1/github/status resolved. Fail closed when the user is unknown, fetch the status from the panel, and add a typed ErrSelfApprove guard in Service.SubmitReview so any path that bypasses the visibility check gets a clean 422 instead of an opaque upstream error. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * test(github): cover controller's self-approve 422 mapping Address PR review feedback: add TestHttpSubmitReview_SelfApproveReturns422 to exercise the controller → service → 422 path end-to-end so a future refactor can't silently reclassify ErrSelfApprove as a generic 500. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Kandev Agent <agent@kandev.dev> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
81 lines
2.5 KiB
Go
81 lines
2.5 KiB
Go
package github
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"testing"
|
|
)
|
|
|
|
// TestService_SubmitReview_RejectsSelfApprove verifies the server-side guard
|
|
// against approving your own PR. GitHub returns a 422 in that case; we catch
|
|
// it server-side so the UI gets a typed error rather than an opaque upstream
|
|
// failure when the frontend's visibility guard is bypassed (e.g. a stale
|
|
// page that didn't see the author update).
|
|
func TestService_SubmitReview_RejectsSelfApprove(t *testing.T) {
|
|
client := NewMockClient()
|
|
client.SetUser("octocat")
|
|
client.AddPR(&PR{
|
|
Number: 7,
|
|
RepoOwner: "octocat",
|
|
RepoName: "hello",
|
|
AuthorLogin: "OCTOCAT", // case-insensitive match
|
|
State: "open",
|
|
})
|
|
svc := newTestService(client)
|
|
|
|
err := svc.SubmitReview(context.Background(), "octocat", "hello", 7, "APPROVE", "")
|
|
if !errors.Is(err, ErrSelfApprove) {
|
|
t.Fatalf("expected ErrSelfApprove, got %v", err)
|
|
}
|
|
if len(client.SubmittedReviews()) != 0 {
|
|
t.Fatalf("expected no review submitted, got %d", len(client.SubmittedReviews()))
|
|
}
|
|
}
|
|
|
|
// TestService_SubmitReview_AllowsOthersPR verifies the guard only blocks the
|
|
// self-approval case — approving someone else's PR must still flow through.
|
|
func TestService_SubmitReview_AllowsOthersPR(t *testing.T) {
|
|
client := NewMockClient()
|
|
client.SetUser("reviewer")
|
|
client.AddPR(&PR{
|
|
Number: 8,
|
|
RepoOwner: "octocat",
|
|
RepoName: "hello",
|
|
AuthorLogin: "octocat",
|
|
State: "open",
|
|
})
|
|
svc := newTestService(client)
|
|
|
|
if err := svc.SubmitReview(context.Background(), "octocat", "hello", 8, "APPROVE", ""); err != nil {
|
|
t.Fatalf("SubmitReview: %v", err)
|
|
}
|
|
reviews := client.SubmittedReviews()
|
|
if len(reviews) != 1 || reviews[0].Event != "APPROVE" {
|
|
t.Fatalf("expected one APPROVE review, got %#v", reviews)
|
|
}
|
|
}
|
|
|
|
// TestService_SubmitReview_CommentOnOwnPRAllowed verifies the guard is
|
|
// scoped to APPROVE — leaving a COMMENT or REQUEST_CHANGES review on your
|
|
// own PR is allowed by GitHub and must not be blocked.
|
|
func TestService_SubmitReview_CommentOnOwnPRAllowed(t *testing.T) {
|
|
client := NewMockClient()
|
|
client.SetUser("octocat")
|
|
client.AddPR(&PR{
|
|
Number: 9,
|
|
RepoOwner: "octocat",
|
|
RepoName: "hello",
|
|
AuthorLogin: "octocat",
|
|
State: "open",
|
|
})
|
|
svc := newTestService(client)
|
|
|
|
if err := svc.SubmitReview(context.Background(), "octocat", "hello", 9, "COMMENT", "looks ok"); err != nil {
|
|
t.Fatalf("SubmitReview: %v", err)
|
|
}
|
|
reviews := client.SubmittedReviews()
|
|
if len(reviews) != 1 || reviews[0].Event != "COMMENT" {
|
|
t.Fatalf("expected one COMMENT review, got %#v", reviews)
|
|
}
|
|
}
|