fix: server lifecycle context [IDE-1791]#1173
Conversation
Done by passing a context to the loading of the configured environment. This will prevent interactive terminals being launched when the server shutsdown. Currently targeting the PR branch in GAF. Change before merge.
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
PR Reviewer Guide 🔍
|
| defer referenceBranchScanWaitGroup.Done() | ||
| isSingleFileScan := pathToScan != folderPath | ||
| scanTypeCtx := ctx2.NewContextWithDeltaScanType(ctx2.Clone(ctx, context.Background()), ctx2.Reference) | ||
| scanTypeCtx := ctx2.NewContextWithDeltaScanType(ctx, ctx2.Reference) |
There was a problem hiding this comment.
We need clone here as we have a deferred cancel of ctx in L226. This means, we need to decouple the reference scan context from the parent, as the reference scan is running async.
|
I spoke with Basti, I am going to wait for his big LS changes, then I will jump on his context enriching in |
| func (c *Config) ServerLifecycleContext() context.Context { | ||
| c.m.RLock() | ||
| defer c.m.RUnlock() | ||
| if c.serverLifecycleCtx == nil { |
There was a problem hiding this comment.
[Should Fix] These accessors panic when the lifecycle context was never set, but newConfig doesn't default-initialize it — only server.Start() and the test helpers do. Production consumers reached deep in background paths (internal/sdk/sdk.go, infrastructure/oss/cli_scanner.go:602 scheduleRefreshScan) call ServerLifecycleContext() unconditionally, so any Config built via config.New/NewFromExtension that triggers a scan without going through Start() (an embedder, or a unit test bypassing the testutil helpers) hard-panics the whole server instead of degrading. Flagged by 3 of 4 reviewers.
Fix: default-initialize the field in newConfig with context.WithCancel(context.Background()) (overwritten by Start), which lets you delete all three panic guards. (Storing a context on the long-lived shared Config singleton is also the containedctx anti-pattern — pragmatic here since Config is the universal handle, but worth a comment.)
— AI review
| defer referenceBranchScanWaitGroup.Done() | ||
| isSingleFileScan := pathToScan != folderPath | ||
| scanTypeCtx := ctx2.NewContextWithDeltaScanType(ctx2.Clone(ctx, context.Background()), ctx2.Reference) | ||
| scanTypeCtx := ctx2.NewContextWithDeltaScanType(ctx, ctx2.Reference) |
There was a problem hiding this comment.
[Should Fix · verify] Binding the reference-branch scan to the parent ctx (instead of the previous Clone(ctx, context.Background()) decoupling) is the right call for shutdown cancellation, but it newly makes the base scan abortable by parent-context cancellation. The base scan does a git checkout (scanBaseBranch → gitCheckoutHandler); if ctx is cancelled mid-checkout the working tree could be left on the reference branch, which was previously impossible. Please confirm every Scan caller passes a lifecycle-bound ctx (not a per-message ctx that cancels on the next request), and that scanBaseBranch restores the branch on cancellation. (3 of 4 reviewers raised this; the WaitGroup makes the normal-completion path safe, the concern is the cancel path.)
— AI review
|
A couple more items from the verification pass (test files; not anchoring inline to keep it readable): [Should Fix] [Suggestion] [Suggestion] Two files solve 'decouple but cancel on shutdown' with different idioms ( Nice catch on the side: — AI review |
| defer referenceBranchScanWaitGroup.Done() | ||
| isSingleFileScan := pathToScan != folderPath | ||
| scanTypeCtx := ctx2.NewContextWithDeltaScanType(ctx2.Clone(ctx, context.Background()), ctx2.Reference) | ||
| scanTypeCtx := ctx2.NewContextWithDeltaScanType(ctx, ctx2.Reference) |
There was a problem hiding this comment.
Worth confirming — semantic change to reference-branch scan cancellation. Previously this cloned onto a fresh context.Background() (ctx2.Clone(ctx, context.Background())), deliberately decoupling the base/reference scan from the parent's cancellation so it always ran to completion and persisted its baseline snapshot. Deriving directly from ctx now places the reference scan in the parent's cancellation tree.
For the shutdown case this is the intended improvement (no detached goroutine). But there's a narrower regression to check: if the parent scan ctx is cancelled by a token change mid-scan (the auth-token-change cancel path), the in-flight base scan now aborts before persistScanResults, so no baseline is persisted and the next delta scan has no baseline — where the old decoupled clone guaranteed completion.
The goroutine lifetime itself is fine (bounded by referenceBranchScanWaitGroup.Wait()). Please confirm aborting the baseline on a token-change cancel is intended. Also worth a comment: cli_scanner.go clones its scheduled-scan base onto the lifecycle ctx, so the two scanners now use different base-ctx strategies — note it so they don't drift.
— AI review
Reviewed
Worth confirming (inline on Suggestions (non-blocking):
Security: no findings introduced; the 60 pre-existing SCA vulns are unchanged by the dep bump and have no available fix. — AI review |
Description
Done by passing a context to the loading of the configured environment.
This will prevent interactive terminals being launched when the server shutsdown.
Currently targeting the PR branch in GAF (snyk/go-application-framework#564). Change before merge.
Checklist
make generate)make lint-fix)