Skip to content

fix(gate): finalize the Gate on a transient 403 at completion - #732

Merged
JSONbored merged 5 commits into
JSONbored:mainfrom
philluiz2323:fix/gate-finalize-on-permission-missing
Jun 17, 2026
Merged

fix(gate): finalize the Gate on a transient 403 at completion#732
JSONbored merged 5 commits into
JSONbored:mainfrom
philluiz2323:fix/gate-finalize-on-permission-missing

Conversation

@philluiz2323

Copy link
Copy Markdown
Contributor

Summary

PR #655 ("never leave the Gittensory Gate check stuck in_progress") wraps gate evaluation in a try/catch so that any failure finalizes the already-posted pending check to a neutral, non-blocking state. That guarantee only covers failures that throw — and a GitHub 403 on the completion call does not throw.

createOrUpdateNamedCheckRun classifies every 403 as a non-throwing permission_missing return:

function isCheckRunPermissionError(error: unknown): boolean {
  ...
  if (e.status === 403) return true; // ALL 403s, including transient secondary-rate-limit
  ...
}

In processors.ts, the completion's permission_missing branch only audited — it didn't finalize and didn't throw. So gateFinalized stayed false, the catch never ran, and the pending in_progress check was orphaned — exactly the multi-hour stuck Gate #655 set out to eliminate.

GitHub returns 403 for transient conditions too (secondary/abuse rate limits — "You have exceeded a secondary rate limit" — and momentary "Resource not accessible by integration"), so this is reachable in normal operation. Crucially, the pending check already posted (pendingGateCheckRunId is set), proving the App had Checks:write at pending time — so a 403 a moment later at completion is almost always transient, not a real revocation, and the correct response is to finalize.

Fix

Finalize the pending check to neutral in the completion's permission_missing branch as well, mirroring the catch:

if (gateCheckResult?.kind === "permission_missing") {
  await auditGateCheckPermissionMissing(...);
  if (pendingGateCheckRunId !== undefined && !gateFinalized) {
    await createOrUpdateErroredGateCheckRun(env, installationId, repoFullName, advisory, { checkRunId: pendingGateCheckRunId }).catch(() => undefined);
    gateFinalized = true;
  }
}

If the 403 was a genuine permission revocation, this finalize PATCH also 403s and is swallowed by .catch(() => undefined) — no worse than today. If it was transient (the common case), the check is correctly closed to neutral and re-runs on the next push.

Tests

The existing queue.test.ts test injects a 500 on the completion PATCH — a 500 throws, so the catch finalized and the test passed, leaving the 403 path uncovered. Added a regression test that stubs the completion PATCH to return 403 ("secondary rate limit") and asserts the same pending check (id 971) is finalized to neutral ("Gittensory Gate — could not finish evaluating") rather than left in_progress.

Full coverage suite green locally (only the known CRLF-local gittensory-focus-manifest test fails locally; passes in CI).

Closes #730

PR JSONbored#655 finalizes the pending in_progress Gate check on any failure that
throws. But a 403 on the completion call is classified as permission_missing
and returns without throwing, so the catch never runs and the pending check
is orphaned in_progress forever.

The pending check already posted (pendingGateCheckRunId is set), proving the
App had Checks:write, so a 403 at completion is almost always a transient
secondary-rate-limit rather than a real revocation. Finalize the pending
check to neutral in the permission_missing branch too (mirroring the catch);
a genuine revocation makes this PATCH 403 as well and it is swallowed.

Closes JSONbored#730
@ghost

ghost commented Jun 14, 2026

Copy link
Copy Markdown

Note

Gittensory Gate skipped

PR closed before full evaluation. No late first comment was created.

Signal Result Evidence Action
Gate result ⚠️ Skipped #732 is no longer open. No action.

💰 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.

@ghost ghost added the gittensory:reviewed label Jun 14, 2026
@ghost

ghost commented Jun 14, 2026

Copy link
Copy Markdown

gittensory · advisory review

Reviewed 2 changed file(s) — two independent AI reviewers.

Changed files: src/queue/processors.ts, test/unit/queue.test.ts

Suggested action:Safe to merge — both reviewers found no blocking issues.

Reviewer A · gpt-oss-120b — recommends ✅ merge
The PR adds a safeguard to finalize a pending Gate check to a neutral state when the completion PATCH returns a transient 403, preventing orphaned in_progress checks. A corresponding unit test verifies the behavior.

Suggestions

  • Consider adding a comment explaining why a neutral conclusion is chosen for transient 403s, for future maintainers.
  • Ensure the new code path is covered by integration tests that run against the real GitHub API mock in CI.

Worth double-checking

  • If createOrUpdateErroredGateCheckRun throws unexpected errors beyond 403, they are silently ignored; verify this is acceptable.
  • Make sure the added neutral conclusion message does not contain any forbidden public terms.

Reviewer B · nemotron-3-120b-a12b — recommends ✅ merge
The PR fixes a race condition where a transient 403 during gate check completion would leave a check run in_progress (orphaned). It adds handling in the permission_missing branch to finalize the pending check to neutral, mirroring the existing error path. The test covers this scenario comprehensively. The change is small, focused, and maintains the public/private boundary (no forbidden terms introduced).

No blocking issues spotted.

@ghost ghost added the gittensory-review label Jun 14, 2026
@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

@ghost ghost removed gittensory-review labels Jun 16, 2026

@JSONbored JSONbored left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR #732 — fix(gate): finalize the Gate on a transient 403 at completion
Author: philluiz2323 | CI: ✅ pass | Status: Failing CI
ACTION: Changes required

Highlights:

  • Real reliability fix: a 403 at the completion PATCH was classified permission_missing (non-throwing), so the pending check was left orphaned in_progress; this finalizes it to neutral.
  • Does NOT change who is blocked — only resolves a stuck check to a non-blocking state; upholds the confirmed-contributor-only Gate invariant.
  • Strong regression test (stubs 403 secondary-rate-limit, asserts check finalized to neutral). Closes #730.

Notes / before merge:

  • mergeable_state: failing CI, please ensure proper test coverage.

@ghost ghost mentioned this pull request Jun 16, 2026
5 tasks
@codecov

codecov Bot commented Jun 16, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 96.69%. Comparing base (e7bb3b3) to head (558d402).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #732   +/-   ##
=======================================
  Coverage   96.69%   96.69%           
=======================================
  Files          94       94           
  Lines       13845    13848    +3     
  Branches     5050     5051    +1     
=======================================
+ Hits        13388    13391    +3     
  Misses         88       88           
  Partials      369      369           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@JSONbored JSONbored left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR #732 — fix(gate): finalize the Gate on a transient 403 at completion
Verdict: MERGE
Resolves issue #730: FULLY
CI: Green where completed (test 2, workers); test 1/lint/ui in_progress at review time, no failures. gittensory neutral.

Highlights:

  • Implements the issue's targeted finalize: in the completion permission_missing branch, when pendingGateCheckRunId is set and !gateFinalized, calls createOrUpdateErroredGateCheckRun (neutral terminal) with .catch(()=>undefined) and sets gateFinalized=true — closing the orphaned-in_progress hole that bypassed the #655 catch.
  • Correctly scoped to the completion-of-already-posted case; a genuine pending-time permission_missing is untouched; a real revocation's finalize PATCH 403 is harmlessly swallowed; gateFinalized guards against double-finalize.
  • Realistic regression test: first completion PATCH 403 ("secondary rate limit"), then asserts a second PATCH on the SAME check id finalizes to completed/neutral — the throw-vs-return gap the old 500-injection test missed.

Concerns / required changes:

  • None blocking — let the mid-run jobs finish green (identical-content jobs + test(2) shard already passed).

Completeness vs issue: Applies the issue's smaller targeted-finalize option and the 403-path regression test; the #655 "never orphan in_progress" guarantee now holds for the transient-403 completion path.

@dosubot dosubot Bot added the lgtm label Jun 17, 2026
@JSONbored
JSONbored merged commit 71a2e0b into JSONbored:main Jun 17, 2026
17 checks passed
@github-project-automation github-project-automation Bot moved this from Todo to Done in gittensory - v1 roadmap Jun 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier.

Projects

No open projects
Status: Done

Development

Successfully merging this pull request may close these issues.

[Bug]: transient 403 on Gate completion leaves check stuck in_progress

2 participants