fix(review): verify linked issue closure source - #5233
Conversation
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #5233 +/- ##
=======================================
Coverage 94.34% 94.34%
=======================================
Files 473 473
Lines 39968 39982 +14
Branches 14570 14576 +6
=======================================
+ Hits 37708 37722 +14
Misses 1585 1585
Partials 675 675
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
|
Caution 🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥🟥 🛑 Gittensory review result - fixes requiredReview updated: 2026-07-12 10:09:49 UTC
🛑 Suggested Action - Manual Review
Review summary Blockers
Nits — 5 non-blocking
Why this is blocked
CI checks failing
Review context
Contributor next steps
Signal definitions
[BETA] Chat with GittensoryAsk Gittensory a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.
Full command reference: https://gittensory.aethereal.dev/docs/gittensory-commands 🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by Gittensory, a quiet PR intelligence layer for OSS maintainers.
|
The prior trust predicate accepted any closed linked issue with closed_at >= pr.merged_at -- spoofable by an unrelated issue that happens to close after the PR merges. Adds fetchLinkedIssueClosedByPullRequest, which reads the issue's GitHub timeline and requires the closing event be attributed to THIS pr number, not just timestamp-eligible. Timeline fetch failures are treated as inconclusive (fail-conservative), never silently stripping existing labels. Also stubs the new /timeline endpoint in queue-5.test.ts's shared stubPropagationFetch helper: every existing caller there exercises the legitimate same-PR-close path (never the new spoofing test, which has its own dedicated stub), so the shared helper can attribute every closure to the PR number already in scope -- without this, all of those pre-existing tests silently lost their propagated labels.
f4e69f4 to
e9f0d6e
Compare
…broken closure check (#5407) fetchLinkedIssueClosedByPullRequest read GitHub's REST /issues/{n}/timeline looking for a source.issue field on "closed" events, but that field never appears there -- only on cross-referenced events. Confirmed against three live production issues (commit_id null, no source key at all). This made the check always fail, turning a rare race into a 100%-reproducing failure on every "Closes #N" merge. Replaced with GraphQL's Issue.timelineItems -> ClosedEvent.closer, verified empirically against live issues. Also fixes two related gaps found during the same investigation: - resolvePrTypeLabel picked the exclusive bug/feature label by config array order (bug always won when both matched an issue's labels) instead of declared precedence. Now the LAST-configured exclusive match wins; operators declare exclusive mappings in ascending precedence order. Updated the two bundled example configs, which still described the old first-wins rule. - maybeReReviewOnLinkedIssueChange only checked isConvergenceRepoAllowed, unlike the periodic sweep, which also falls back to isAgentConfigured(settings.autonomy). Aligned the two gates, short-circuited so the common allowlisted case never pays for the extra settings fetch. Closes #5385
Motivation
closed_at >= pr.merged_at, which can be spoofed by an unrelated issue that happens to close after a PR and enable label/reward gaming.Description
fetchLinkedIssueClosedByPullRequestinsrc/github/backfill.tsthat reads/issues/{n}/timelineand detects a closing event sourced from the given PR.closedAt >= prMergedAtshortcut with a two-step check insrc/review/linked-issue-label-propagation-fetch.tsthat requires timeline attribution for timestamp-eligible closed issues.inconclusive(fail-conservative) so transient errors do not silently strip existing labels.fetchLinkedIssueLabelsForPropagationto accept and forwardprNumberand add regression tests intest/unit/linked-issue-label-propagation-fetch.test.tscovering the legitimate same-PR close path, unrelated post-merge spoofing, missingprNumbercontext, and timeline fetch failures.Testing
npx vitest run test/unit/linked-issue-label-propagation-fetch.test.tsand all tests in that file passed.npm run typecheckand it passed.npm run test:coveragebut the run hit unrelatedtest/unit/queue.test.tstimeouts and global coverage thresholds failed in this environment, so global coverage was not verified here.npm audit --audit-level=moderatebut the registry audit endpoint returned403 Forbiddenin this environment.Codex Task