Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 2 additions & 113 deletions core/cli/federated.go

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Security Critical

In federation.go handleConn, if tunnelAddresses is empty (no online nodes), rand.IntN(0) panics with a divide-by-zero, crashing the goroutine and potentially the process; add a length check and close the connection before returning.

Suggested fix
	if len(tunnelAddresses) == 0 {
		log.Error().Msg("No online tunnel nodes available")
		conn.Close()
		return
	}
	tunnelAddr := tunnelAddresses[rand.IntN(len(tunnelAddresses))]
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/cli/federated.go
Lines: 100-104
Issue Type: security-critical
Severity: critical

Issue Description:
In `federation.go` `handleConn`, if `tunnelAddresses` is empty (no online nodes), `rand.IntN(0)` panics with a divide-by-zero, crashing the goroutine and potentially the process; add a length check and close the connection before returning.

Current Code:
	tunnelAddr := tunnelAddresses[rand.IntN(len(tunnelAddresses))]

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,9 @@ package cli

import (
"context"
"errors"
"fmt"
"io"
"net"
"time"

"math/rand/v2"

cliContext "github.com/mudler/LocalAI/core/cli/context"
"github.com/mudler/LocalAI/core/p2p"
"github.com/mudler/edgevpn/pkg/node"
"github.com/mudler/edgevpn/pkg/protocol"
"github.com/mudler/edgevpn/pkg/types"
"github.com/rs/zerolog/log"
)

type FederatedCLI struct {
Expand All @@ -24,107 +13,7 @@ type FederatedCLI struct {
}

func (f *FederatedCLI) Run(ctx *cliContext.Context) error {
fs := p2p.NewFederatedServer(f.Address, p2p.FederatedID, f.Peer2PeerToken)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Functional Critical

In a non-p2p build, running the federated CLI now always fails with "not implemented" because this caller was switched to FederatedServer.Start while the new implementation exists only in the p2p-only file; trigger: build without the p2p tag and execute the federated command.

Either move the real FederatedServer.Start implementation into an untagged file, add the same build tag to the CLI command so it is unavailable without p2p, or preserve the previous non-tagged implementation path.

Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/cli/federated.go
Lines: 16-16
Issue Type: functional-critical
Severity: critical

Issue Description:
In a non-p2p build, running the federated CLI now always fails with "not implemented" because this caller was switched to FederatedServer.Start while the new implementation exists only in the p2p-only file; trigger: build without the `p2p` tag and execute the federated command.

Current Code:
fs := p2p.NewFederatedServer(f.Address, p2p.FederatedID, f.Peer2PeerToken)

return fs.Start(context.Background())

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira


n, err := p2p.NewNode(f.Peer2PeerToken)
if err != nil {
return fmt.Errorf("creating a new node: %w", err)
}
err = n.Start(context.Background())
if err != nil {
return fmt.Errorf("creating a new node: %w", err)
}

if err := p2p.ServiceDiscoverer(context.Background(), n, f.Peer2PeerToken, p2p.FederatedID, nil); err != nil {
return err
}

return Proxy(context.Background(), n, f.Address, p2p.FederatedID)
}

func Proxy(ctx context.Context, node *node.Node, listenAddr, service string) error {

log.Info().Msgf("Allocating service '%s' on: %s", service, listenAddr)
// Open local port for listening
l, err := net.Listen("tcp", listenAddr)
if err != nil {
log.Error().Err(err).Msg("Error listening")
return err
}
// ll.Info("Binding local port on", srcaddr)

ledger, _ := node.Ledger()

// Announce ourselves so nodes accepts our connection
ledger.Announce(
ctx,
10*time.Second,
func() {
// Retrieve current ID for ip in the blockchain
//_, found := ledger.GetKey(protocol.UsersLedgerKey, node.Host().ID().String())
// If mismatch, update the blockchain
//if !found {
updatedMap := map[string]interface{}{}
updatedMap[node.Host().ID().String()] = &types.User{
PeerID: node.Host().ID().String(),
Timestamp: time.Now().String(),
}
ledger.Add(protocol.UsersLedgerKey, updatedMap)
// }
},
)

defer l.Close()
for {
select {
case <-ctx.Done():
return errors.New("context canceled")
default:
log.Debug().Msg("New for connection")
// Listen for an incoming connection.
conn, err := l.Accept()
if err != nil {
fmt.Println("Error accepting: ", err.Error())
continue
}

// Handle connections in a new goroutine, forwarding to the p2p service
go func() {
var tunnelAddresses []string
for _, v := range p2p.GetAvailableNodes(p2p.FederatedID) {
if v.IsOnline() {
tunnelAddresses = append(tunnelAddresses, v.TunnelAddress)
} else {
log.Info().Msgf("Node %s is offline", v.ID)
}
}

// open a TCP stream to one of the tunnels
// chosen randomly
// TODO: optimize this and track usage
tunnelAddr := tunnelAddresses[rand.IntN(len(tunnelAddresses))]

tunnelConn, err := net.Dial("tcp", tunnelAddr)
if err != nil {
log.Error().Err(err).Msg("Error connecting to tunnel")
return
}

log.Info().Msgf("Redirecting %s to %s", conn.LocalAddr().String(), tunnelConn.RemoteAddr().String())
closer := make(chan struct{}, 2)
go copyStream(closer, tunnelConn, conn)
go copyStream(closer, conn, tunnelConn)
<-closer

tunnelConn.Close()
conn.Close()
// ll.Infof("(service %s) Done handling %s", serviceID, l.Addr().String())
}()
}
}

}

func copyStream(closer chan struct{}, dst io.Writer, src io.Reader) {
defer func() { closer <- struct{}{} }() // connection is closed, send signal to stop proxy
io.Copy(dst, src)
return fs.Start(context.Background())

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Functional High

The new code passes context.Background() instead of the CLI-provided context, so cancellation signals (e.g., SIGINT) from the caller are ignored and the server cannot be gracefully shut down.

Suggested change
return fs.Start(context.Background())
return fs.Start(ctx.Context)
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/cli/federated.go
Lines: 18-18
Issue Type: functional-high
Severity: high

Issue Description:
The new code passes `context.Background()` instead of the CLI-provided context, so cancellation signals (e.g., SIGINT) from the caller are ignored and the server cannot be gracefully shut down.

Current Code:
	return fs.Start(context.Background())

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Robustness High

The new code passes context.Background() instead of the CLI-provided context, so cancellation signals (e.g., SIGINT) from the caller are ignored and the server cannot be gracefully shut down.

Suggested change
return fs.Start(context.Background())
return fs.Start(ctx.Context)
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/cli/federated.go
Lines: 18-18
Issue Type: robustness-high
Severity: high

Issue Description:
The new code passes `context.Background()` instead of the CLI-provided context, so cancellation signals (e.g., SIGINT) from the caller are ignored and the server cannot be gracefully shut down.

Current Code:
	return fs.Start(context.Background())

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Functional High

The Run method ignores the incoming ctx parameter and passes context.Background() to fs.Start, preventing proper cancellation or shutdown propagation from the CLI framework.

Suggested change
return fs.Start(context.Background())
return fs.Start(ctx.Context)
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/cli/federated.go
Lines: 18-18
Issue Type: functional-high
Severity: high

Issue Description:
The `Run` method ignores the incoming `ctx` parameter and passes `context.Background()` to `fs.Start`, preventing proper cancellation or shutdown propagation from the CLI framework.

Current Code:
	return fs.Start(context.Background())

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Functional High

This ignores the CLI context and starts the server with a detached background context, so shutdown and cancellation will not propagate; pass the provided context instead.

Suggested change
return fs.Start(context.Background())
return fs.Start(ctx)
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/cli/federated.go
Lines: 18-18
Issue Type: functional-high
Severity: high

Issue Description:
This ignores the CLI context and starts the server with a detached background context, so shutdown and cancellation will not propagate; pass the provided context instead.

Current Code:
	return fs.Start(context.Background())

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

}
13 changes: 13 additions & 0 deletions core/p2p/federatedServer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package p2p

type FederatedServer struct {
listenAddr, service, p2ptoken string
}

func NewFederatedServer(listenAddr, service, p2pToken string) *FederatedServer {
return &FederatedServer{
listenAddr: listenAddr,
service: service,
p2ptoken: p2pToken,
}
}
Comment on lines +7 to +13

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Security High

The p2p token is stored as a plain string field with no validation or sanitization; an empty or malformed token passed to NewFederatedServer will propagate silently and be used to initialize a network node, potentially allowing unauthenticated federation. Add a non-empty check and return an error or panic early.

Suggested fix
func NewFederatedServer(listenAddr, service, p2pToken string) (*FederatedServer, error) {
	if p2pToken == "" {
		return nil, fmt.Errorf("p2pToken must not be empty")
	}
	if listenAddr == "" {
		return nil, fmt.Errorf("listenAddr must not be empty")
	}
	return &FederatedServer{
		listenAddr: listenAddr,
		service:    service,
		p2ptoken:   p2pToken,
	}, nil
}
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/p2p/federatedServer.go
Lines: 7-13
Issue Type: security-high
Severity: high

Issue Description:
The p2p token is stored as a plain string field with no validation or sanitization; an empty or malformed token passed to NewFederatedServer will propagate silently and be used to initialize a network node, potentially allowing unauthenticated federation. Add a non-empty check and return an error or panic early.

Current Code:
func NewFederatedServer(listenAddr, service, p2pToken string) *FederatedServer {
	return &FederatedServer{
		listenAddr: listenAddr,
		service:    service,
		p2ptoken:   p2pToken,
	}
}

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

127 changes: 127 additions & 0 deletions core/p2p/federation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
//go:build p2p
// +build p2p

package p2p

import (
"context"
"errors"
"fmt"
"io"
"net"
"time"

"github.com/rs/zerolog/log"

"math/rand/v2"

"github.com/mudler/edgevpn/pkg/node"
"github.com/mudler/edgevpn/pkg/protocol"
"github.com/mudler/edgevpn/pkg/types"
)

func (fs *FederatedServer) Start(ctx context.Context) error {
n, err := NewNode(fs.p2ptoken)
if err != nil {
return fmt.Errorf("creating a new node: %w", err)
}
err = n.Start(ctx)
if err != nil {
return fmt.Errorf("starting a new node: %w", err)
}

if err := ServiceDiscoverer(ctx, n, fs.p2ptoken, FederatedID, nil); err != nil {
Comment on lines +28 to +33

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Node started twice before service discovery

FederatedServer.Start calls n.Start(ctx) on line 28, then ServiceDiscovererdiscoveryTunnels (in p2p.go) calls n.Start(ctx) a second time on the same node instance. This mirrors the original FederatedCLI.Run behaviour but is carried forward here. Depending on how edgevpn's node.Start handles duplicate calls (panic, error, or silent no-op), this could result in unexpected runtime behaviour.

return err
}

return fs.proxy(ctx, n)
}

func (fs *FederatedServer) proxy(ctx context.Context, node *node.Node) error {

log.Info().Msgf("Allocating service '%s' on: %s", fs.service, fs.listenAddr)
// Open local port for listening
l, err := net.Listen("tcp", fs.listenAddr)
if err != nil {
log.Error().Err(err).Msg("Error listening")
return err
}
// ll.Info("Binding local port on", srcaddr)

ledger, _ := node.Ledger()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Robustness High

The error returned by node.Ledger() is silently discarded with _; a nil ledger will cause a nil-pointer panic on the subsequent ledger.Announce call.

Suggested fix
	ledger, err := node.Ledger()
	if err != nil {
		log.Error().Err(err).Msg("Error getting ledger")
		return err
	}
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/p2p/federation.go
Lines: 51-51
Issue Type: robustness-high
Severity: high

Issue Description:
The error returned by `node.Ledger()` is silently discarded with `_`; a nil ledger will cause a nil-pointer panic on the subsequent `ledger.Announce` call.

Current Code:
	ledger, _ := node.Ledger()

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Robustness High

The error from node.Ledger() is silently discarded with _; if ledger acquisition fails, subsequent calls on the nil ledger will panic.

Suggested fix
	ledger, err := node.Ledger()
	if err != nil {
		log.Error().Err(err).Msg("Error getting ledger")
		return err
	}
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/p2p/federation.go
Lines: 51-51
Issue Type: robustness-high
Severity: high

Issue Description:
The error from `node.Ledger()` is silently discarded with `_`; if ledger acquisition fails, subsequent calls on the nil ledger will panic.

Current Code:
	ledger, _ := node.Ledger()

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Robustness High

The error return from node.Ledger() is silently discarded; if ledger acquisition fails, subsequent calls on a nil ledger will panic.

Suggested fix
	ledger, err := node.Ledger()
	if err != nil {
		return fmt.Errorf("getting ledger: %w", err)
	}
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/p2p/federation.go
Lines: 51-51
Issue Type: robustness-high
Severity: high

Issue Description:
The error return from `node.Ledger()` is silently discarded; if ledger acquisition fails, subsequent calls on a nil ledger will panic.

Current Code:
	ledger, _ := node.Ledger()

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira


// Announce ourselves so nodes accepts our connection
ledger.Announce(
ctx,
10*time.Second,
func() {
// Retrieve current ID for ip in the blockchain
//_, found := ledger.GetKey(protocol.UsersLedgerKey, node.Host().ID().String())
// If mismatch, update the blockchain
//if !found {
updatedMap := map[string]interface{}{}
updatedMap[node.Host().ID().String()] = &types.User{
PeerID: node.Host().ID().String(),
Timestamp: time.Now().String(),
}
ledger.Add(protocol.UsersLedgerKey, updatedMap)
// }
},
)

defer l.Close()
for {
select {
case <-ctx.Done():
return errors.New("context canceled")
default:
log.Debug().Msg("New for connection")
// Listen for an incoming connection.
conn, err := l.Accept()
if err != nil {
fmt.Println("Error accepting: ", err.Error())
continue
}

// Handle connections in a new goroutine, forwarding to the p2p service
go handleConn(conn)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Performance High

Spawning an unbounded goroutine for every accepted connection allows trivial resource exhaustion, so enforce a concurrency limit or backpressure before launching handleConn.

Suggested fix
			select {
			case sem <- struct{}{}:
				go func() {
					defer func() { <-sem }()
					handleConn(conn)
				}()
			default:
				log.Error().Msg("Too many concurrent connections")
				conn.Close()
			}
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/p2p/federation.go
Lines: 87-87
Issue Type: performance-high
Severity: high

Issue Description:
Spawning an unbounded goroutine for every accepted connection allows trivial resource exhaustion, so enforce a concurrency limit or backpressure before launching handleConn.

Current Code:
			go handleConn(conn)

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

}
}
Comment on lines +73 to +89

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Performance High

The proxy accept loop spins in the default branch without blocking, consuming 100% CPU when no connections arrive; l.Accept() already blocks, but the surrounding select with a default case means the goroutine never yields to the scheduler between the context check and the blocking Accept call on a busy loop iteration: replace with a blocking accept and a separate context-cancellation mechanism.

Suggested fix
	go func() {
		<-ctx.Done()
		l.Close()
	}()
	for {
		conn, err := l.Accept()
		if err != nil {
			select {
			case <-ctx.Done():
				return errors.New("context canceled")
			default:
				log.Error().Err(err).Msg("Error accepting")
				continue
			}
		}
		go handleConn(conn)
	}
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/p2p/federation.go
Lines: 73-89
Issue Type: performance-high
Severity: high

Issue Description:
The `proxy` accept loop spins in the `default` branch without blocking, consuming 100% CPU when no connections arrive; `l.Accept()` already blocks, but the surrounding `select` with a `default` case means the goroutine never yields to the scheduler between the context check and the blocking `Accept` call on a busy loop iteration: replace with a blocking accept and a separate context-cancellation mechanism.

Current Code:
	for {
		select {
		case <-ctx.Done():
			return errors.New("context canceled")
		default:
			log.Debug().Msg("New for connection")
			conn, err := l.Accept()
			if err != nil {
				fmt.Println("Error accepting: ", err.Error())
				continue
			}
			go handleConn(conn)
		}
	}

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

Comment on lines +73 to +89

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Robustness Medium

When l.Accept() returns an error after context cancellation, the loop continues to the default branch and calls l.Accept() again instead of exiting; check ctx.Done() before retrying or use a non-blocking select with a timeout.

Suggested fix
	for {
		select {
		case <-ctx.Done():
			return errors.New("context canceled")
		default:
		}
		log.Debug().Msg("New for connection")
		conn, err := l.Accept()
		if err != nil {
			select {
			case <-ctx.Done():
				return errors.New("context canceled")
			default:
			}
			log.Error().Err(err).Msg("Error accepting connection")
			continue
		}
		go handleConn(conn)
	}
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/p2p/federation.go
Lines: 73-89
Issue Type: robustness-medium
Severity: medium

Issue Description:
When `l.Accept()` returns an error after context cancellation, the loop continues to the `default` branch and calls `l.Accept()` again instead of exiting; check `ctx.Done()` before retrying or use a non-blocking select with a timeout.

Current Code:
	for {
		select {
		case <-ctx.Done():
			return errors.New("context canceled")
		default:
			log.Debug().Msg("New for connection")
			conn, err := l.Accept()
			if err != nil {
				fmt.Println("Error accepting: ", err.Error())
				continue
			}
			go handleConn(conn)
		}
	}

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

Comment on lines +73 to +89

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Robustness Medium

l.Accept() blocks indefinitely in the default branch, so the ctx.Done() case is never reached while waiting for a connection; use a deadline or a separate goroutine to make context cancellation responsive.

Suggested fix
	go func() {
		<-ctx.Done()
		l.Close()
	}()
	for {
		conn, err := l.Accept()
		if err != nil {
			select {
			case <-ctx.Done():
				return errors.New("context canceled")
			default:
				log.Error().Err(err).Msg("Error accepting")
				continue
			}
		}
		go handleConn(conn)
	}
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/p2p/federation.go
Lines: 73-89
Issue Type: robustness-medium
Severity: medium

Issue Description:
`l.Accept()` blocks indefinitely in the `default` branch, so the `ctx.Done()` case is never reached while waiting for a connection; use a deadline or a separate goroutine to make context cancellation responsive.

Current Code:
	for {
		select {
		case <-ctx.Done():
			return errors.New("context canceled")
		default:
			log.Debug().Msg("New for connection")
			// Listen for an incoming connection.
			conn, err := l.Accept()
			if err != nil {
				fmt.Println("Error accepting: ", err.Error())
				continue
			}
			// Handle connections in a new goroutine, forwarding to the p2p service
			go handleConn(conn)
		}
	}

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira


}

func handleConn(conn net.Conn) {
var tunnelAddresses []string
for _, v := range GetAvailableNodes(FederatedID) {
if v.IsOnline() {
tunnelAddresses = append(tunnelAddresses, v.TunnelAddress)
} else {
log.Info().Msgf("Node %s is offline", v.ID)
}
}

// open a TCP stream to one of the tunnels
// chosen randomly
// TODO: optimize this and track usage
tunnelAddr := tunnelAddresses[rand.IntN(len(tunnelAddresses))]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Panic when no online nodes are available

If all federated nodes are offline, tunnelAddresses is empty and rand.IntN(0) panics at runtime. The refactoring extracted this into a standalone handleConn function, preserving the crash path. Any incoming connection when the cluster has no live members will terminate the goroutine with a panic rather than returning a clean error to the caller.

Comment on lines +103 to +106

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 After collecting online addresses, add a guard before calling rand.IntN so an empty slice does not cause a panic. The connection should be closed cleanly with a log message instead.

Suggested change
// open a TCP stream to one of the tunnels
// chosen randomly
// TODO: optimize this and track usage
tunnelAddr := tunnelAddresses[rand.IntN(len(tunnelAddresses))]
// open a TCP stream to one of the tunnels
// chosen randomly
// TODO: optimize this and track usage
if len(tunnelAddresses) == 0 {
log.Error().Msg("No online tunnel nodes available")
conn.Close()
return
}
tunnelAddr := tunnelAddresses[rand.IntN(len(tunnelAddresses))]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Functional Critical

If tunnelAddresses is empty (no online nodes), rand.IntN(0) panics with a runtime error; add a guard before indexing.

Suggested fix
	if len(tunnelAddresses) == 0 {
		log.Error().Msg("No online tunnel nodes available")
		conn.Close()
		return
	}
	tunnelAddr := tunnelAddresses[rand.IntN(len(tunnelAddresses))]
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/p2p/federation.go
Lines: 106-106
Issue Type: functional-critical
Severity: critical

Issue Description:
If `tunnelAddresses` is empty (no online nodes), `rand.IntN(0)` panics with a runtime error; add a guard before indexing.

Current Code:
	tunnelAddr := tunnelAddresses[rand.IntN(len(tunnelAddresses))]

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Functional Critical

If tunnelAddresses is empty, rand.IntN(0) panics with a runtime error; add a guard to close the connection and return early when no online nodes are available.

Suggested fix
	if len(tunnelAddresses) == 0 {
		log.Error().Msg("No online tunnel nodes available")
		conn.Close()
		return
	}
	tunnelAddr := tunnelAddresses[rand.IntN(len(tunnelAddresses))]
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/p2p/federation.go
Lines: 106-106
Issue Type: functional-critical
Severity: critical

Issue Description:
If `tunnelAddresses` is empty, `rand.IntN(0)` panics with a runtime error; add a guard to close the connection and return early when no online nodes are available.

Current Code:
	tunnelAddr := tunnelAddresses[rand.IntN(len(tunnelAddresses))]

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Functional Critical

tunnelAddresses may be empty when no nodes are online, causing rand.IntN(0) to panic with an index-out-of-range; add a guard before indexing.

Suggested fix
	if len(tunnelAddresses) == 0 {
		log.Error().Msg("No online tunnel nodes available")
		conn.Close()
		return
	}
	tunnelAddr := tunnelAddresses[rand.IntN(len(tunnelAddresses))]
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/p2p/federation.go
Lines: 106-106
Issue Type: functional-critical
Severity: critical

Issue Description:
`tunnelAddresses` may be empty when no nodes are online, causing `rand.IntN(0)` to panic with an index-out-of-range; add a guard before indexing.

Current Code:
	tunnelAddr := tunnelAddresses[rand.IntN(len(tunnelAddresses))]

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Functional Critical

Selecting a random tunnel without checking for an empty list can panic, so return early when no online federated nodes are available.

Suggested fix
	if len(tunnelAddresses) == 0 {
		log.Error().Msg("No online federated nodes available")
		conn.Close()
		return
	}
	tunnelAddr := tunnelAddresses[rand.IntN(len(tunnelAddresses))]
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/p2p/federation.go
Lines: 106-106
Issue Type: functional-critical
Severity: critical

Issue Description:
Selecting a random tunnel without checking for an empty list can panic, so return early when no online federated nodes are available.

Current Code:
	tunnelAddr := tunnelAddresses[rand.IntN(len(tunnelAddresses))]

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Functional Critical

Selecting a random tunnel without checking for an empty slice will panic, so return early when no online nodes are available.

Suggested fix
	if len(tunnelAddresses) == 0 {
		log.Error().Msg("No online federated nodes available")
		conn.Close()
		return
	}
	tunnelAddr := tunnelAddresses[rand.IntN(len(tunnelAddresses))]
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/p2p/federation.go
Lines: 106-106
Issue Type: functional-critical
Severity: critical

Issue Description:
Selecting a random tunnel without checking for an empty slice will panic, so return early when no online nodes are available.

Current Code:
	tunnelAddr := tunnelAddresses[rand.IntN(len(tunnelAddresses))]

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Functional Critical

Selecting a random tunnel from an empty slice panics, so return early when no online federated nodes are available.

Suggested fix
	if len(tunnelAddresses) == 0 {
		log.Error().Msg("No online federated nodes available")
		conn.Close()
		return
	}
	tunnelAddr := tunnelAddresses[rand.IntN(len(tunnelAddresses))]
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/p2p/federation.go
Lines: 106-106
Issue Type: functional-critical
Severity: critical

Issue Description:
Selecting a random tunnel from an empty slice panics, so return early when no online federated nodes are available.

Current Code:
	tunnelAddr := tunnelAddresses[rand.IntN(len(tunnelAddresses))]

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Functional Critical

Selecting a tunnel with rand.IntN(len(tunnelAddresses)) panics when no online federated nodes are available, so guard the empty slice and close the client connection cleanly.

Suggested fix
	if len(tunnelAddresses) == 0 {
		log.Error().Msg("No online federated nodes available")
		conn.Close()
		return
	}
	tunnelAddr := tunnelAddresses[rand.IntN(len(tunnelAddresses))]
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/p2p/federation.go
Lines: 106-106
Issue Type: functional-critical
Severity: critical

Issue Description:
Selecting a tunnel with rand.IntN(len(tunnelAddresses)) panics when no online federated nodes are available, so guard the empty slice and close the client connection cleanly.

Current Code:
	tunnelAddr := tunnelAddresses[rand.IntN(len(tunnelAddresses))]

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira


tunnelConn, err := net.Dial("tcp", tunnelAddr)
Comment on lines +97 to +108

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Security High

TunnelAddress values sourced from the distributed ledger (untrusted peers) are passed directly to net.Dial without validation, allowing a malicious peer to redirect connections to arbitrary internal hosts (SSRF).

Suggested fix
			// Validate that tunnelAddr resolves to an expected loopback/VPN range before dialing.
			// Example: parse host and verify it is within the allowed CIDR before appending.
					host, _, err := net.SplitHostPort(v.TunnelAddress)
					if err != nil {
						log.Warn().Msgf("Skipping invalid tunnel address %s", v.TunnelAddress)
						continue
					}
					ip := net.ParseIP(host)
					if ip == nil || !allowedCIDR.Contains(ip) {
						log.Warn().Msgf("Tunnel address %s outside allowed range, skipping", v.TunnelAddress)
						continue
					}
					tunnelAddresses = append(tunnelAddresses, v.TunnelAddress)
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/p2p/federation.go
Lines: 97-108
Issue Type: security-high
Severity: high

Issue Description:
`TunnelAddress` values sourced from the distributed ledger (untrusted peers) are passed directly to `net.Dial` without validation, allowing a malicious peer to redirect connections to arbitrary internal hosts (SSRF).

Current Code:
			tunnelAddresses = append(tunnelAddresses, v.TunnelAddress)
		}
	}

	tunnelAddr := tunnelAddresses[rand.IntN(len(tunnelAddresses))]

	tunnelConn, err := net.Dial("tcp", tunnelAddr)

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

if err != nil {
log.Error().Err(err).Msg("Error connecting to tunnel")
return
Comment on lines +108 to +111

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Robustness High

The accepted client connection is left open on dial failure, so close it before returning.

Suggested fix
	tunnelConn, err := net.Dial("tcp", tunnelAddr)
	if err != nil {
		log.Error().Err(err).Msg("Error connecting to tunnel")
		conn.Close()
		return
	}
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/p2p/federation.go
Lines: 108-111
Issue Type: robustness-high
Severity: high

Issue Description:
The accepted client connection is left open on dial failure, so close it before returning.

Current Code:
	tunnelConn, err := net.Dial("tcp", tunnelAddr)
	if err != nil {
		log.Error().Err(err).Msg("Error connecting to tunnel")
		return
	}

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

Comment on lines +108 to +111

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Robustness High

The accepted client connection is leaked when net.Dial fails, so close conn before returning on this error path.

Suggested fix
	tunnelConn, err := net.Dial("tcp", tunnelAddr)
	if err != nil {
		log.Error().Err(err).Msg("Error connecting to tunnel")
		conn.Close()
		return
	}
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/p2p/federation.go
Lines: 108-111
Issue Type: robustness-high
Severity: high

Issue Description:
The accepted client connection is leaked when net.Dial fails, so close conn before returning on this error path.

Current Code:
	tunnelConn, err := net.Dial("tcp", tunnelAddr)
	if err != nil {
		log.Error().Err(err).Msg("Error connecting to tunnel")
		return
	}

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

Comment on lines +108 to +111

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Robustness High

The accepted client connection is leaked on dial failure, so close conn before returning.

Suggested fix
	tunnelConn, err := net.Dial("tcp", tunnelAddr)
	if err != nil {
		log.Error().Err(err).Msg("Error connecting to tunnel")
		conn.Close()
		return
	}
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/p2p/federation.go
Lines: 108-111
Issue Type: robustness-high
Severity: high

Issue Description:
The accepted client connection is leaked on dial failure, so close conn before returning.

Current Code:
	tunnelConn, err := net.Dial("tcp", tunnelAddr)
	if err != nil {
		log.Error().Err(err).Msg("Error connecting to tunnel")
		return
	}

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

Comment on lines +108 to +111

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Robustness High

The accepted client connection is leaked on tunnel dial failure, so close conn before returning from the error path.

Suggested fix
	tunnelConn, err := net.Dial("tcp", tunnelAddr)
	if err != nil {
		log.Error().Err(err).Msg("Error connecting to tunnel")
		conn.Close()
		return
	}
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/p2p/federation.go
Lines: 108-111
Issue Type: robustness-high
Severity: high

Issue Description:
The accepted client connection is leaked on tunnel dial failure, so close conn before returning from the error path.

Current Code:
	tunnelConn, err := net.Dial("tcp", tunnelAddr)
	if err != nil {
		log.Error().Err(err).Msg("Error connecting to tunnel")
		return
	}

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

}
Comment on lines +108 to +112

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Robustness High

When handleConn returns early after a dial error, conn is never closed, leaking the accepted connection.

Suggested fix
	tunnelConn, err := net.Dial("tcp", tunnelAddr)
	if err != nil {
		log.Error().Err(err).Msg("Error connecting to tunnel")
		conn.Close()
		return
	}
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/p2p/federation.go
Lines: 108-112
Issue Type: robustness-high
Severity: high

Issue Description:
When `handleConn` returns early after a dial error, `conn` is never closed, leaking the accepted connection.

Current Code:
	tunnelConn, err := net.Dial("tcp", tunnelAddr)
	if err != nil {
		log.Error().Err(err).Msg("Error connecting to tunnel")
		return
	}

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira


log.Info().Msgf("Redirecting %s to %s", conn.LocalAddr().String(), tunnelConn.RemoteAddr().String())
closer := make(chan struct{}, 2)
go copyStream(closer, tunnelConn, conn)
go copyStream(closer, conn, tunnelConn)
<-closer

tunnelConn.Close()
conn.Close()
}

func copyStream(closer chan struct{}, dst io.Writer, src io.Reader) {
defer func() { closer <- struct{}{} }() // connection is closed, send signal to stop proxy
io.Copy(dst, src)
}
Comment on lines +124 to +127

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Robustness Medium

io.Copy errors are silently ignored in copyStream; log or surface the error so connection failures are observable.

Suggested fix
func copyStream(closer chan struct{}, dst io.Writer, src io.Reader) {
	defer func() { closer <- struct{}{} }() // connection is closed, send signal to stop proxy
	if _, err := io.Copy(dst, src); err != nil {
		log.Debug().Err(err).Msg("copyStream error")
	}
}
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert go developer with deep knowledge of security, performance, and best practices.

### Context

File: core/p2p/federation.go
Lines: 124-127
Issue Type: robustness-medium
Severity: medium

Issue Description:
`io.Copy` errors are silently ignored in `copyStream`; log or surface the error so connection failures are observable.

Current Code:
func copyStream(closer chan struct{}, dst io.Writer, src io.Reader) {
	defer func() { closer <- struct{}{} }() // connection is closed, send signal to stop proxy
	io.Copy(dst, src)
}

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow go best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue Jira

6 changes: 0 additions & 6 deletions core/p2p/p2p.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"context"
"errors"
"fmt"
"io"
"net"
"os"
"sync"
Expand Down Expand Up @@ -137,11 +136,6 @@ func allocateLocalService(ctx context.Context, node *node.Node, listenAddr, serv

}

func copyStream(closer chan struct{}, dst io.Writer, src io.Reader) {
defer func() { closer <- struct{}{} }() // connection is closed, send signal to stop proxy
io.Copy(dst, src)
}

// This is the main of the server (which keeps the env variable updated)
// This starts a goroutine that keeps LLAMACPP_GRPC_SERVERS updated with the discovered services
func ServiceDiscoverer(ctx context.Context, n *node.Node, token, servicesID string, discoveryFunc func()) error {
Expand Down
4 changes: 4 additions & 0 deletions core/p2p/p2p_disabled.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ func GenerateToken() string {
return "not implemented"
}

func (fs *FederatedServer) Start(ctx context.Context) error {
return fmt.Errorf("not implemented")
}

func ServiceDiscoverer(ctx context.Context, node *node.Node, token, servicesID string, fn func()) error {
return fmt.Errorf("not implemented")
}
Expand Down