Skip to content

Small improvements to cmd/root#1734

Merged
rumpl merged 1 commit intodocker:mainfrom
dgageot:cmdroot
Feb 16, 2026
Merged

Small improvements to cmd/root#1734
rumpl merged 1 commit intodocker:mainfrom
dgageot:cmdroot

Conversation

@dgageot
Copy link
Member

@dgageot dgageot commented Feb 14, 2026

No description provided.

Signed-off-by: David Gageot <david.gageot@docker.com>
@dgageot dgageot requested a review from a team as a code owner February 14, 2026 13:35
Copy link

@docker-agent docker-agent bot left a comment

Choose a reason for hiding this comment

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

Review Summary

Found 1 critical bug and 1 potential issue in this PR.

Critical: The change on line 126 in cmd/root/api.go removes a nil check for recordCleanup, which will cause a nil pointer panic when the --record flag is not specified (the common case).

Medium: The new listenAndCloseOnCancel helper function has a design that could lead to goroutine leaks if used with long-lived contexts, though current usage is safe.

} else if recordCleanup != nil {
} else {
defer func() {
if err := recordCleanup(); err != nil {
Copy link

Choose a reason for hiding this comment

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

🚨 CRITICAL BUG: Nil pointer dereference

The code unconditionally calls recordCleanup() without checking if it's nil. When the --record flag is not specified (the common case), setupRecordingProxy returns a nil recordCleanup function, and calling it here will cause a panic.

Evidence: In cmd/root/run.go (lines 228-236), the same setupRecordingProxy function is used but the defer is guarded with if cassettePath != "" {, indicating that recordCleanup can be nil.

Fix: Restore the nil check:

} else if recordCleanup != nil {
    defer func() {
        if err := recordCleanup(); err != nil {
            slog.Error("Failed to cleanup recording proxy", "error", err)
        }
    }()
}

Or follow the pattern from run.go and check if the cassette path is non-empty before deferring the cleanup.

if err != nil {
return nil, fmt.Errorf("failed to listen on %s: %w", addr, err)
}
go func() {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential goroutine leak

While the current usage is safe (all callers pass cmd.Context() which is cancelled on command exit), this function design could lead to goroutine leaks if used with long-lived contexts in the future.

The spawned goroutine waits indefinitely for ctx.Done() with no timeout. If a parent context that outlives the listener is passed, the goroutine will leak.

Suggestion: Consider adding a comment documenting that this function requires a context that will be cancelled when the listener is no longer needed, or refactor to use a more robust cleanup pattern.

@rumpl rumpl merged commit d8f01f7 into docker:main Feb 16, 2026
8 checks passed
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.

3 participants