feat(orb): dispatch config_push relay rows separately from the GitHub-webhook queue#7615
Conversation
…-webhook queue drainOrbRelayWithMonitor's per-event loop now branches on kind BEFORE calling args.enqueue (which unconditionally does JSON.parse(rawBody) as GitHubWebhookPayload): a 'config_push' row routes to a new dedicated handleConfigPushRelayEvent (receive-and-log only, per #4902's v1 scope -- no capability-toggle or config-mutation side effect implemented here). Everything else -- 'github_webhook' and any old-shaped/missing kind -- falls through to the existing path unchanged. Threads `kind` through the read side that feeds the drain loop: pullRelayPending's SELECT + RelayPendingEvent, the /v1/orb/relay/pull response (no code change needed there -- it just returns pullRelayPending's output), and drainOrbRelay's HTTP response parsing (defaults a missing `kind` to 'github_webhook' for a rolling deploy against an older Orb server). Closes #7523
selfhost-metrics.test.ts scans every incr() call site for its metric name and cross-checks it against DEFAULT_METRIC_META -- loopover_orb_config_push_received_total (introduced in the previous commit) was missing.
|
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 @@
## feat/config-push-write-path #7615 +/- ##
===============================================================
- Coverage 88.51% 88.49% -0.02%
===============================================================
Files 724 724
Lines 75976 75990 +14
Branches 22614 22616 +2
===============================================================
+ Hits 67247 67250 +3
- Misses 7681 7688 +7
- Partials 1048 1052 +4
Flags with carried forward coverage won't be shown. Click here to find out more.
|
|
Tip ✅ LoopOver review result - approve/merge recommendedReview updated: 2026-07-21 03:22:13 UTC
Review summary Nits — 5 non-blocking
Decision drivers
Context & advisory signals — never blocks the verdict
Review context
Contributor next steps
Signal definitions
🧪 Chat with LoopOverAsk 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.
Full command reference: https://loopover.ai/docs/loopover-commands 🧪 Experimental — new and may change. 🟩 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.
|
Closes the codecov/patch gap on PR #7615 -- handleConfigPushRelayEvent's error-logging ternary (error instanceof Error ? error.message : String(error)) only had its Error-instance arm exercised.
…-webhook queue (#7615) * feat(orb): dispatch config_push relay rows separately from the GitHub-webhook queue drainOrbRelayWithMonitor's per-event loop now branches on kind BEFORE calling args.enqueue (which unconditionally does JSON.parse(rawBody) as GitHubWebhookPayload): a 'config_push' row routes to a new dedicated handleConfigPushRelayEvent (receive-and-log only, per #4902's v1 scope -- no capability-toggle or config-mutation side effect implemented here). Everything else -- 'github_webhook' and any old-shaped/missing kind -- falls through to the existing path unchanged. Threads `kind` through the read side that feeds the drain loop: pullRelayPending's SELECT + RelayPendingEvent, the /v1/orb/relay/pull response (no code change needed there -- it just returns pullRelayPending's output), and drainOrbRelay's HTTP response parsing (defaults a missing `kind` to 'github_webhook' for a rolling deploy against an older Orb server). Closes #7523 * chore(orb): register the config_push relay metric selfhost-metrics.test.ts scans every incr() call site for its metric name and cross-checks it against DEFAULT_METRIC_META -- loopover_orb_config_push_received_total (introduced in the previous commit) was missing. * test(selfhost): cover the non-Error branch of the config_push throw log Closes the codecov/patch gap on PR #7615 -- handleConfigPushRelayEvent's error-logging ternary (error instanceof Error ? error.message : String(error)) only had its Error-instance arm exercised.
…7611) * feat(orb): add a typed config-push write path to the relay pipeline Adds a discriminator column (kind, default 'github_webhook') to orb_relay_pending so the pull-drain loop can eventually tell an operator-addressed config-push notice apart from a GitHub webhook row (dispatch side is a separate follow-up). A new POST /v1/app/fleet/config-push endpoint lets an operator enqueue a typed { pushId, message, capability?, deprecatesAt? } payload for an explicit list of installation_ids, mirroring the kill-switch endpoint's requireAppRole + zod-validated-body pattern. Placed under /v1/app/*, not /v1/internal/* (the latter's own middleware requires a bearer INTERNAL_JOB_TOKEN and never resolves a session identity for it, which would make requireAppRole's session-role branch unreachable for a control-panel caller -- see the route's own doc comment). Write side only: enqueueConfigPushRelay shares the same TTL pruning and per-installation backlog cap as the existing webhook path, but skips its GitHubWebhookPayload-shaped coalesce-key derivation entirely (a config_push payload never has that shape). No existing webhook-row behavior changes. Closes #7522 * feat(orb): dispatch config_push relay rows separately from the GitHub-webhook queue (#7615) * feat(orb): dispatch config_push relay rows separately from the GitHub-webhook queue drainOrbRelayWithMonitor's per-event loop now branches on kind BEFORE calling args.enqueue (which unconditionally does JSON.parse(rawBody) as GitHubWebhookPayload): a 'config_push' row routes to a new dedicated handleConfigPushRelayEvent (receive-and-log only, per #4902's v1 scope -- no capability-toggle or config-mutation side effect implemented here). Everything else -- 'github_webhook' and any old-shaped/missing kind -- falls through to the existing path unchanged. Threads `kind` through the read side that feeds the drain loop: pullRelayPending's SELECT + RelayPendingEvent, the /v1/orb/relay/pull response (no code change needed there -- it just returns pullRelayPending's output), and drainOrbRelay's HTTP response parsing (defaults a missing `kind` to 'github_webhook' for a rolling deploy against an older Orb server). Closes #7523 * chore(orb): register the config_push relay metric selfhost-metrics.test.ts scans every incr() call site for its metric name and cross-checks it against DEFAULT_METRIC_META -- loopover_orb_config_push_received_total (introduced in the previous commit) was missing. * test(selfhost): cover the non-Error branch of the config_push throw log Closes the codecov/patch gap on PR #7615 -- handleConfigPushRelayEvent's error-logging ternary (error instanceof Error ? error.message : String(error)) only had its Error-instance arm exercised. * fix(review): prune the relay backlog once per config-push request, not per target enqueueConfigPushRelay pruned the shared orb_relay_pending table on every call, but the route fans it out over up to 500 installationIds via Promise.all -- turning one request into up to 500 redundant global TTL-prune scans/deletes. Moves the prune to the route handler, called once before the fan-out; enqueueConfigPushRelay no longer prunes itself.
Summary
kind-column PR) — this diffs against that branch, notmain, since thekindcolumn andConfigPushPayloadshape are prerequisites. Please merge feat(orb): add a typed config-push write path to the relay pipeline #7611 first; this PR's base will need to move tomainafterward (or GitHub will auto-retarget once feat(orb): add a typed config-push write path to the relay pipeline #7611 merges and its branch is deleted).drainOrbRelayWithMonitor's per-event loop (src/selfhost/monitored-work.ts) now branches onev.kindbefore callingargs.enqueue(which unconditionally doesJSON.parse(rawBody) as GitHubWebhookPayload): a'config_push'row routes to a new dedicatedhandleConfigPushRelayEvent— receive-and-log only, per Add a config-push/rollout-control write path to fleet analytics #4902's explicit v1 scope (no capability-toggle or config-mutation side effect implemented here). Everything else —'github_webhook'and any old-shaped/missingkind— falls through to the existing path unchanged.kindthrough the whole read side that feeds the drain loop:pullRelayPending's SELECT +RelayPendingEventtype (src/orb/relay.ts), the/v1/orb/relay/pullresponse (no code change needed there — it just returnspullRelayPending's output), anddrainOrbRelay's HTTP response parsing (src/orb/broker-client.ts) — defaults a missingkindto'github_webhook'so a rolling deploy against an older Orb server never misroutes an old-shaped event.loopover_orb_config_push_received_total, registered insrc/selfhost/metrics.ts.Test plan
npm run typechecknpm run ui:openapi:checktest/integration/orb-relay.test.ts/test/unit/orb-broker-client.test.tsfixtures for the new requiredkindfield (all existing assertions otherwise byte-identical — the webhook path's behavior did not change)test/unit/selfhost-monitored-work.test.ts(describe("kind-based dispatch (#7523)")): a'github_webhook'row AND a legacy row with nokindat all both still dispatch through the exact existingenqueueWebhookByEnvpath unchanged; a'config_push'row reaches the new handler instead and never callsenqueue; malformed JSON in a config_pushrawBodysurfaces aspayload: nullinstead of throwing; a throwing handler doesn't abort the rest of the batch and isn't acked (mirrors the existing enqueue-isolation regression test); default console.log sink parity with the webhook pathCloses #7523