Skip to content

Commit c2c8697

Browse files
fix(queue): terminalize active-review tracking in synchronize-amendment close guard (#8015) (#8044)
Co-authored-by: rsnetworkinginc <rsnetworkinginc@users.noreply.github.com>
1 parent b3bd0ba commit c2c8697

2 files changed

Lines changed: 20 additions & 0 deletions

File tree

src/queue/review-evasion.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1365,4 +1365,6 @@ async function closeSynchronizeAmendmentIfPolicyEnabled(
13651365
/* v8 ignore next -- fail-safe: an audit write failure never blocks the handler. */
13661366
() => undefined,
13671367
);
1368+
/* v8 ignore next -- best-effort: the guarded CAS update never rejects against a healthy D1, and a cleanup failure here must never block the webhook. */
1369+
await terminalizeActiveReviewTracking(env, repoFullName, pr.number, { onlyIfHeadSha: pr.headSha }).catch(() => undefined);
13681370
}

test/unit/queue-lifecycle-guards.test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3922,6 +3922,24 @@ describe("review-evasion protection (#review-evasion-protection)", () => {
39223922
expect(audit?.detail).toContain("contributor");
39233923
});
39243924

3925+
it("terminalizes the active-review tracking row on enforcement close -- leaves no dangling row for the PR's reviewed headSha, matching the four sibling guards", async () => {
3926+
const calls: Array<{ url: string; method: string }> = [];
3927+
stubEvasionFetch(calls);
3928+
const env = createTestEnv({ GITHUB_APP_PRIVATE_KEY: generateRsaPrivateKeyPem(), GITHUB_APP_SLUG: "loopover-orb" });
3929+
await setupEvasionRepo(env, { reviewEvasionProtection: "off", synchronizeClosePolicy: "close" });
3930+
// A review was actively tracked on the PR's head before the author pushed the amending commit; the
3931+
// synchronize-amendment close must mark that row terminal, exactly as its four siblings do.
3932+
await repositoriesModule.startActiveReviewTracking(env, { repoFullName: "JSONbored/gittensory", pullNumber: 42, headSha: "def456", authorLogin: "contributor", deliveryId: "review-start-sync" });
3933+
expect(await repositoriesModule.hasActiveReviewForHeadSha(env, "JSONbored/gittensory", 42, "def456")).toBe(true);
3934+
3935+
await processJob(env, { type: "github-webhook", deliveryId: "sync-policy-terminalize", eventName: "pull_request", payload: synchronizePayload("contributor") });
3936+
3937+
expect(calls.some((c) => c.method === "PATCH" && c.url.endsWith("/pulls/42"))).toBe(true);
3938+
const audit = await env.DB.prepare("select outcome from audit_events where event_type = ?").bind("github_app.synchronize_amend_closed").first<{ outcome: string }>();
3939+
expect(audit?.outcome).toBe("completed");
3940+
expect(await repositoriesModule.hasActiveReviewForHeadSha(env, "JSONbored/gittensory", 42, "def456")).toBe(false); // terminalized
3941+
});
3942+
39253943
it("does NOT record a moderation strike -- this is a blanket policy against an ordinary push, not a detected abuse pattern", async () => {
39263944
const calls: Array<{ url: string; method: string }> = [];
39273945
stubEvasionFetch(calls);

0 commit comments

Comments
 (0)