Skip to content

fix(orb): guard the trailing webhook-event record write in handleOrbWebhook - #8934

Merged
JSONbored merged 2 commits into
JSONbored:mainfrom
shin-core:fix/orb-webhook-guard-trailing-event-write-8883
Jul 26, 2026
Merged

fix(orb): guard the trailing webhook-event record write in handleOrbWebhook#8934
JSONbored merged 2 commits into
JSONbored:mainfrom
shin-core:fix/orb-webhook-guard-trailing-event-write-8883

Conversation

@shin-core

Copy link
Copy Markdown
Contributor

What & why

Closes #8883.

src/orb/webhook.ts's handleOrbWebhook wraps the upsertOrbInstallation + recordOrbPrOutcome
writes in a try/catch that turns a DB-write failure into a clean 500 {error:"processing_failed"}
plus a logged orb_webhook_processing_failed event. The very next DB write —
recordOrbWebhookEvent(..., status:"received") — had no such guard. If it threw, the 202
response below was never reached, the delivery went unrecorded (so a GitHub redelivery re-ran the
already-successful upsert/outcome processing, with zero visibility into why), and no structured log
was emitted for this specific mode.

Change

Wrap the trailing write in its own try/catch with a distinct orb_webhook_event_record_failed
error log and a clean 500 {error:"event_record_failed"}, so GitHub redelivers and the row is
retried — mirroring the processing-failed handling above while keeping the two modes distinguishable
(processing succeeded vs the event row failed to record).

Validation

  • New integration test in test/integration/orb-webhook.test.ts: throws only on the trailing
    orb_webhook_events INSERT (upsert/outcome succeed, dedup read succeeds), asserts a clean
    500 {error:"event_record_failed"}, the distinct orb_webhook_event_record_failed log with the
    identifying fields, and that orb_webhook_processing_failed is not logged.
  • Bug-catch verified: unwrapping the guard fails exactly the new test (unhandled rejection past the
    202).
  • 100% patch coverage on the new catch path (success path covered by existing tests).

…ebhook

The status:"received" recordOrbWebhookEvent write ran outside the try/catch that
wraps the upsert/outcome writes above it. If it threw, execution never reached the
202 response, the delivery went unrecorded (so a GitHub redelivery re-ran the
already-successful upsert/outcome processing) and no structured log was emitted for
this specific failure mode.

Wrap the trailing write in its own try/catch with a distinct
orb_webhook_event_record_failed error log and a clean 500 { error:
"event_record_failed" }, so GitHub redelivers and retries the row -- mirroring the
processing-failed handling above while keeping the two failure modes distinguishable.

Closes JSONbored#8883
@shin-core
shin-core requested a review from JSONbored as a code owner July 26, 2026 13:45
@superagent-security

Copy link
Copy Markdown
Contributor

🚨 Contributor flagged. Click here for more info: Superagent Dashboard

@superagent-security superagent-security Bot added the contributor:flagged Contributor flagged for review by trust analysis. label Jul 26, 2026
@superagent-security

Copy link
Copy Markdown
Contributor

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

@loopover-orb loopover-orb Bot added the gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier. label Jul 26, 2026
@loopover-orb

loopover-orb Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Warning

⏸️ LoopOver review result - manual review recommended

Review updated: 2026-07-26 14:16:15 UTC

2 files · 1 AI reviewer · no blockers · CI green · unstable

⏸️ Suggested Action - Manual Review

Review summary
This closes #8883 by wrapping the previously-unguarded trailing `recordOrbWebhookEvent(..., status:"received")` write in its own try/catch, mirroring the existing processing-failed pattern above it with a distinct `orb_webhook_event_record_failed` log and a `500 {error:"event_record_failed"}` response so GitHub redelivers instead of the delivery silently vanishing. The fix is correct and traceable: prior to this change an exception here would propagate unguarded past the 202 return, and the new integration test genuinely exercises the real path by throwing only on the `orb_webhook_events` INSERT while letting the upsert/outcome writes and dedup SELECT hit the real DB, then asserts both the distinct log and the absence of the other log. The `console.error(JSON.stringify(...))` pattern and 200-char message truncation match the existing sibling catch block exactly, so this is a well-targeted, narrow, low-risk fix.

Nits — 3 non-blocking
  • The `String(error).slice(0, 200)` truncation is copied verbatim from the sibling catch block above — consider extracting a small shared helper to log these two near-identical structured-error blocks and avoid drift if the format changes later (src/orb/webhook.ts:83-90 vs :91-98).
  • The external brief's flag of `200`/`500` as 'magic numbers' is not meaningful here — `500` is the HTTP status already used identically in the sibling catch two lines above, and `200` is the pre-existing truncation length reused verbatim; no new constant is warranted.
  • Consider a tiny shared `logOrbWebhookError(event, eventMeta, error)` helper for the two structured-error logs to keep them in lockstep going forward (src/orb/webhook.ts).

Decision drivers

  • ✅ Code review — No blockers (1 reviewer)
  • ✅ Gate result — Passing (No configured blocker found.)
Context & advisory signals — never blocks the verdict
Signal Result Evidence
Linked issue ✅ Linked #8883
Related work ✅ No active overlap found No same-issue or scoped active PR overlap found.
Change scope ✅ 20/20 Low review scope from cached public metadata (1 linked issue).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 40 registered-repo PR(s), 25 merged, 0 issue(s).
Contributor context ✅ Confirmed Gittensor contributor shin-core; Gittensor profile; 40 PR(s), 0 issue(s).
Improvement ✅ Minor risk: clean · value: minor
Linked issue satisfaction

Addressed
The diff wraps the trailing recordOrbWebhookEvent call in its own try/catch with a distinct orb_webhook_event_record_failed structured log and a clean 500 response, matching the pattern used above it, and adds an integration test that throws specifically on that write and asserts the clean response plus the distinct log (and absence of the other log).

Review context
  • Author: shin-core
  • Role context: outside_contributor
  • Public audience mode: oss maintainer
  • Lane context: Repository is configured for direct PR review.
  • Public profile languages: TypeScript, JavaScript, Solidity, Dart, Python, CSS, PHP, Rust
  • Official Gittensor activity: 40 PR(s), 0 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Start here: Triage stale or unlinked PRs.
Signal definitions
  • Related work = same linked issue, overlapping active PRs, or title/path similarity.
  • Change scope = cached public metadata such as size labels, draft state, and review-burden hints.
  • Validation posture = whether the PR provides enough public validation/test evidence for maintainer review.
  • Contributor workload = public contributor activity and cleanup pressure, not a repo-wide quality failure.
  • Contributor context = public GitHub/Gittensor identity context; non-Gittensor status is not a blocker.
🧪 Chat with LoopOver

Ask LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.

  • @loopover ask <question> answers contribution-quality Q&A with source citations and freshness.
  • @loopover chat <question> answers in natural prose from cached decision-pack facts via local inference (maintainer/collaborator; read-only).
  • A plain-language @loopover mention with a real question is routed to the closest matching read-only command automatically — no exact syntax required.

Full command reference: https://loopover.ai/docs/loopover-commands

🧪 Experimental — new and may change.

Decision record
  • action: hold · clause: success
  • config: 03a7f8b529a9 · pack: oss-anti-slop
  • record: c9cc762ebc53 (schema v2, head bf1b7ff)

🟩 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 LoopOver, a quiet PR intelligence layer for OSS maintainers.

  • Re-run LoopOver review

@codecov

codecov Bot commented Jul 26, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.58%. Comparing base (32ee72e) to head (94f7245).
⚠️ Report is 3 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8934      +/-   ##
==========================================
+ Coverage   90.56%   90.58%   +0.02%     
==========================================
  Files          96       97       +1     
  Lines       22490    22554      +64     
  Branches     3884     3903      +19     
==========================================
+ Hits        20367    20431      +64     
  Misses       1945     1945              
  Partials      178      178              
Flag Coverage Δ
backend 100.00% <100.00%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
src/orb/webhook.ts 100.00% <100.00%> (ø)

@loopover-orb loopover-orb Bot added the manual-review Gittensor contributor context label Jul 26, 2026
@loopover-orb

loopover-orb Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Held for manual review: the gate and required CI are green, but GitHub reports this pull request's mergeable state as unstable because a non-required check or status is not passing, so LoopOver will not auto-merge. A maintainer can resolve the failing check or review and merge manually. This is an automated maintenance action.

@JSONbored
JSONbored merged commit 14c8907 into JSONbored:main Jul 26, 2026
7 of 8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contributor:flagged Contributor flagged for review by trust analysis. gittensor:bug Gittensor-scored bug fix — scores a 0.05x multiplier. manual-review Gittensor contributor context

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(orb): handleOrbWebhook's trailing recordOrbWebhookEvent write is unguarded, unlike the write two lines above it

2 participants