Skip to content

Conversation

@bcho
Copy link
Member

@bcho bcho commented Jan 2, 2026

Summary

  • add support for listening on Unix domain sockets via a new --http-socket flag
  • ensure the server starts, cleans up, and logs correctly when using a socket
  • add automated coverage and documentation for socket-based serving

Testing

  • go test ./...

Codex Task

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds support for listening on Unix domain sockets to the SQLite REST server, providing an alternative to TCP-based networking. The implementation allows users to specify a socket path via the --http-socket flag, with proper setup, logging, and cleanup of socket resources.

Key Changes

  • Added --http-socket CLI flag to enable Unix socket listening as an alternative to TCP (takes precedence over --http-addr)
  • Implemented socket lifecycle management including directory creation, stale socket cleanup, listener management, and graceful shutdown
  • Added comprehensive test coverage for Unix socket functionality

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.

File Description
server.go Core implementation adding SocketPath field to ServerOptions, listener field to dbServer struct, and modified Start() method to support both TCP and Unix socket listening with proper cleanup
server_socket_test.go New test file validating Unix socket server functionality including socket creation, HTTP communication over Unix domain sockets, and basic query operations
README.md Documentation update with example usage of the new --http-socket flag

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 89 to 90
close(done)
}
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

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

After closing the done channel, the test immediately ends without waiting for the server to complete its shutdown sequence. This could lead to a race condition where the test cleanup (t.TempDir() cleanup) happens before the server finishes shutting down and cleaning up the socket. Consider adding a small delay or a synchronization mechanism to ensure the server has completed its shutdown before the test exits.

Copilot uses AI. Check for mistakes.
return
}

if err := os.RemoveAll(server.socket); err != nil {
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

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

Using RemoveAll to clean up a socket file is dangerous and could accidentally delete an entire directory if the socket path is misconfigured. Use os.Remove instead, which will fail safely if the path is a directory.

Suggested change
if err := os.RemoveAll(server.socket); err != nil {
if err := os.Remove(server.socket); err != nil && !errors.Is(err, os.ErrNotExist) {

Copilot uses AI. Check for mistakes.
Comment on lines 89 to 90
close(done)
}
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

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

The test doesn't verify that the Unix socket file is properly cleaned up after the server shuts down. Consider adding an assertion after closing the done channel and allowing some time for cleanup to verify that the socket file no longer exists, ensuring the cleanup logic in the Start method works correctly.

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

}
}

if err := os.RemoveAll(server.socket); err != nil {
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

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

Using os.RemoveAll on a socket path could be dangerous if the path points to a directory. Consider using os.Remove instead, which will fail safely if the path is a directory. This prevents accidentally deleting an entire directory structure if misconfigured.

Suggested change
if err := os.RemoveAll(server.socket); err != nil {
if err := os.Remove(server.socket); err != nil && !errors.Is(err, os.ErrNotExist) {

Copilot uses AI. Check for mistakes.

server.logger.Info("shutting down server")
shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

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

The listener is not explicitly closed during shutdown. Although server.Shutdown will close the listener, explicitly closing it ensures proper cleanup and makes the code more maintainable. Add a check and close the listener before or after the Shutdown call.

Suggested change
defer cancel()
defer cancel()
if server.listener != nil {
if err := server.listener.Close(); err != nil && !errors.Is(err, net.ErrClosed) {
server.logger.Error(err, "failed to close listener")
}
}

Copilot uses AI. Check for mistakes.
return
}

l, err := net.Listen("unix", server.socket)
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

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

The socket file permissions (0666 by default for Unix sockets) could be a security concern. Consider setting explicit restrictive permissions after creating the socket using os.Chmod to limit access to the socket file (e.g., 0600 for owner-only or 0660 for owner and group).

Copilot uses AI. Check for mistakes.
}
server.listener = l

go server.server.Serve(l)
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

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

The error returned by server.Serve is not captured or logged. While Serve is called in a goroutine, consider capturing and logging the error for better observability, especially to distinguish between expected shutdown (http.ErrServerClosed) and unexpected errors.

Copilot uses AI. Check for mistakes.
}
server.listener = l

go server.server.Serve(l)
Copy link

Copilot AI Jan 2, 2026

Choose a reason for hiding this comment

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

The error returned by server.Serve is not captured or logged. While Serve is called in a goroutine, consider capturing and logging the error for better observability, especially to distinguish between expected shutdown (http.ErrServerClosed) and unexpected errors.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants