Skip to content

Sync 2 Inkeep OSS Changes - #833

Merged
inkeep-oss-sync[bot] merged 2 commits into
mainfrom
copybara/sync
Jul 27, 2026
Merged

Sync 2 Inkeep OSS Changes#833
inkeep-oss-sync[bot] merged 2 commits into
mainfrom
copybara/sync

Conversation

@inkeep-oss-sync

Copy link
Copy Markdown
Contributor

Copybara-translated 2 Inkeep OSS changes. Rebase-merge this PR so the prepared commits land directly on public main.

Commits:

  • fix(auth): survive a dropped sign-in stream instead of failing ([Bug]: Connection with Github #803) (#2928)
  • ci(open-knowledge): make Stable the terminal Linear release stage (#2750)

mike-inkeep and others added 2 commits July 27, 2026 19:04
… (#2928)

* fix(auth): survive a dropped sign-in stream instead of failing (#803)

GitHub sign-in failed with "Sign-in stream ended without confirmation"
when the loopback connection between the browser and the local server
blipped. Two things turned a transient drop into a permanent failure.

The stream carried zero bytes from the moment the device code appeared
until authorization finished, which is what idle-connection reapers look
for: SSL-inspection agents, VPN local proxies, tab-backgrounding. The
envelope now heartbeats a ping line every 15s; consumers skip it and it
never terminates the stream.

The disconnect also SIGTERM'd the device-flow subprocess, so a user who
authorized on github.com afterwards stored no token and had nothing to
recover. A disconnect is now a detach: the flow runs on and the client
reconnects via the auth-status relay to pick up a token that landed
while it was gone. The property the old kill protected, don't store a
token after the user backed out, moves onto an explicit signal:
POST /api/local-op/auth/cancel, which the modal fires on close. That is
the lifetime model the desktop IPC transport already had, where a
vanished renderer never killed the flow and only an explicit cancel did;
HTTP was the outlier because a socket close was the only signal it had.

Also drives the countdown off the expires_in GitHub actually issued. It
counted down from a hardcoded 2 minutes and claimed "Code expired" while
the code had ~13 minutes left, which was also the window in which
recovery could succeed. The device-flow subprocess timeout moves to 16
minutes for the same reason: 10 minutes cut the flow short of the code's
own life.

* refactor(auth): drop the cancel slot guard, back off recovery polls

Two follow-ups from self-review of the #803 fix.

The cancel endpoint had a concurrency slot like its local-op siblings,
but those guard a subprocess spawn and this one spawns nothing and does
no IO. Its body runs with no await in it, so two concurrent cancels
cannot interleave and the second reads a null slot and no-ops. The guard
bought nothing and added a failure mode that inverts the endpoint's
purpose: a 429'd cancel leaves the flow running, which is exactly what
the caller asked to stop. Wrapped in catchErrors so an unexpected throw
still lands as a typed 500.

Recovery polling now backs off 2s to 10s instead of a fixed 3s. Each
poll spawns an auth status subprocess server-side, so a fixed interval
cost ~300 spawns across a code's full 15-minute life. Backoff keeps that
under ~100 while the early polls, when the user is most likely to be
finishing up, stay fast.

* fix(auth): make stream detach and recovery-probe failures observable

Both from review. The recovery loop swallowed every status-probe error,
so a recovery that was broken the whole time and a user who simply never
authorized both ended at the same expiry message 15 minutes later, with
nothing to tell them apart. It warns now, matching the bounded-warn
pattern the NDJSON line-drop in the same file uses.

Server-side, a detached flow was invisible until something displaced it.
It now logs a structured auth-stream-detached event, but only for a
GENUINE detach. An unconditional log would fire on every normal cancel
too: the client POSTs the cancel and then aborts the stream, so the
socket closes while the child is still winding down from the SIGTERM. A
detach event that fires on routine teardown tells an operator nothing
about whether an intermediary is cutting streams. The slot-ownership
check is what separates the two, since an explicit cancel has already
cleared the slot and a displaced flow no longer owns it.

The cancel test now mirrors the real client's POST-then-abort ordering,
which is what makes that check load-bearing; without it the test goes
red.

* fix(auth): log a failed cancel POST

Third observability item from review, same class as the other two. A
cancel that never lands leaves a device-flow child running for up to 16
minutes, and the environments this fix targets are exactly the ones
where a loopback POST might not make it. Still best-effort: the flow's
own timeout and fresh-start displacement remain the backstops.

GitOrigin-RevId: 09df6361d357b68d762ec9360072d34a095b8c7e
…750)

Two-channel model: stable = production = done. Beta cut advances the Linear
release to the started 'Beta' stage; stable promotion just completes it, landing
in the pipeline's completed stage (renamed from 'Released' to 'Stable'). Drops
the intermediate 'update stage=Stable' so there's no confusing third state.

Requires (one-time, Linear UI): delete the started 'Stable' stage, then rename
the completed 'Released' stage to 'Stable'.

GitOrigin-RevId: 4d6362b721517ed1a545e4fbcc1990f63bf0f95f
@inkeep-oss-sync
inkeep-oss-sync Bot requested a review from nick-inkeep as a code owner July 27, 2026 19:05
@inkeep-oss-sync
inkeep-oss-sync Bot merged commit 9fa3a9a into main Jul 27, 2026
@inkeep-oss-sync
inkeep-oss-sync Bot deleted the copybara/sync branch July 27, 2026 19:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants