Skip to content

Add fork identity wait plumbing#298

Open
sjmiller609 wants to merge 1 commit into
mainfrom
hypeship/fork-identity-wait
Open

Add fork identity wait plumbing#298
sjmiller609 wants to merge 1 commit into
mainfrom
hypeship/fork-identity-wait

Conversation

@sjmiller609

@sjmiller609 sjmiller609 commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add optional fork identity wait mode, enabled by KERNEL_FORK_IDENTITY_WAIT=true
  • add internal API routes for host-injected identity:
    • POST /internal/fork-identity
    • GET /internal/fork-identity/config
  • add shared forkidentity payload/env/path helpers
  • update wrapper startup so Chrome and kernel-images-api can stay warm while wrapper waits for identity, then apply identity-bound env before starting identity-bound services

Default Behavior

No behavior changes unless KERNEL_FORK_IDENTITY_WAIT=true is set.

Without that env:

  • wrapper startup does not wait for a fork identity payload
  • identity injection returns conflict
  • config reads return not found when no payload exists
  • kernel-images-api follows the existing startup/restart path

Tests

  • go test ./cmd/api ./cmd/wrapper ./lib/forkidentity -count=1
  • git diff --check

Note

Medium Risk
Touches VM boot sequencing, process env (JWT/instance URLs), and new internal HTTP injection endpoints; gated off by default but security-sensitive when enabled on fork restores.

Overview
Adds optional fork identity wait mode (KERNEL_FORK_IDENTITY_WAIT=true) so restored snapshots can receive per-instance identity from the host before identity-bound services run.

Introduces server/lib/forkidentity for payload validation, file paths under /run/kernel/, env mapping/clearing, and extension config (instance name + metro/session intel URL precedence).

API: POST /internal/fork-identity accepts a JSON payload, writes it atomically, and blocks until the wrapper applies it (applied marker). GET /internal/fork-identity/config returns extension config when ready, 202 Accepted while waiting, or 404 when wait mode is off and no payload exists.

Wrapper: Replaces the prior FORK HOOK placeholder. In wait mode, Chrome and kernel-images-api start early (CDP stays warm), the wrapper stops envoy, polls for the payload file, applies env to the process, writes the applied marker, then runs init-envoy without restarting the API. Shutdown cancels the startup wait via context.

Default boot path is unchanged when the env flag is unset.

Reviewed by Cursor Bugbot for commit 252875c. Bugbot is set up for automated code reviews on this repo. Configure here.

@sjmiller609 sjmiller609 marked this pull request as ready for review June 25, 2026 15:07
@sjmiller609 sjmiller609 requested a review from hiroTamada June 25, 2026 15:07

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 3 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 252875c. Configure here.

// services use `restart` so the same code path works for boot (start a
// stopped service) and post-fork (stop+start to force a re-read of
// refreshed envs).
if !waitForForkIdentityIfEnabled(startupCtx, forkIdentityWait) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Early POST loses payload

High Severity

With fork identity wait enabled, kernel-images-api starts early and can accept and persist a fork identity payload. The wrapper then deletes the payload file, leading to a race where an injected payload is immediately removed, causing injections to fail and boot to stall until retried.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 252875c. Configure here.

restartAll("kernel-images-api")
if !forkIdentityWait {
restartAll("kernel-images-api")
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

API keeps pre-identity env

Medium Severity

In fork identity wait mode, kernel-images-api starts before identity is applied and isn't restarted. Since it loads configuration like S2 basin, token, and stream only at process start, fork-injected identity environment variables are not picked up. This can result in stale or disabled S2 telemetry streams.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 252875c. Configure here.

w.WriteHeader(http.StatusAccepted)
return
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale config without wait mode

Low Severity

When fork-identity wait is disabled, GET /internal/fork-identity/config returns 200 with JSON whenever fork-identity.json exists, without checking the applied marker. A leftover payload from a snapshot or prior run can expose the wrong instance or metro URL to consumers that treat 200 as authoritative.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 252875c. Configure here.

@hiroTamada hiroTamada left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

approved — reviewed as opt-in plumbing.

everything is gated behind KERNEL_FORK_IDENTITY_WAIT. with it unset the boot path is unchanged: the if forkIdentityWait branches are skipped, kernel-images-api is still restarted in the identity phase, and the two new internal routes answer 409/404. traced the default path end to end — WaitEnabled() returns (false, nil) on empty env, so there's no error/fatal and no wait. the forkidentity lib is self-contained and unit-tested.

one non-blocking nit:

  • forkidentity/payload.go WaitAppliedMarker and wrapper/fork_identity.go waitForForkIdentityPayload busy-spin with runtime.Gosched() and no sleep, so they peg a core for up to the 30s timeout. the other wrapper wait loops (waitForSocket, waitForHTTPProbe) use time.Sleep(20ms) — worth matching for consistency.

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