ronantakizawa/codereview-bench huggingface dataset:
Repository: hashicorp/nomad
File: command/job_start.go (Go)

Code before:
			}

			// Check if the job exists and has been stopped (status is dead)
			jobId, namespace, err := c.JobIDByPrefix(client, jobID, nil)
			if err != nil {
				c.Ui.Error(err.Error())
				statusCh <- 1
				return
			}
			job, err := c.JobByPrefix(client, jobId, nil)
			if err != nil {
				c.Ui.Error(err.Error())
				statusCh <- 1
				return
			}
			if *job.Status != "dead" {
				c.Ui.Info(fmt.Sprintf("Job  %v has not been stopped and has the following status: %v", *job.Name, *job.Status))
				statusCh <- 0
				return

			}

			// Get all versions associated to current job
			q := &api.QueryOptions{Namespace: namespace}

			versions, _, _, err := client.Jobs().Versions(jobID, true, q)
			if err != nil {
				c.Ui.Error(fmt.Sprintf("Error retrieving job versions: %s", err))
				statusCh <- 1
			}

			// Find the most recent running version for this job
			var chosenIndex uint64
			versionAvailable := false
			for i := len(versions) - 1; i >= 0; i-- {
				if *versions[i].Status == "running" && *versions[i].Stop {
					chosenIndex = uint64(i)
					versionAvailable = true
					break
				}

			}
			if !versionAvailable {
				c.Ui.Error(fmt.Sprintf("No previous running versions of job %v,  %s", *job.Name, err))
				statusCh <- 1
				return
			}

			// Parse the Consul token
			if consulToken == "" {
				// Check the environment variable

Review comment (bug):
And now because we have the `Job` object, we can refer to its ID field directly and know that we're never going to use the wrong one in this function:

```suggestion
			versions, _, _, err := client.Jobs().Versions(job.ID, true, q)
```

Code after:
	multiregion := job.IsMultiregion()
	if detach || periodic || paramjob || multiregion {
		c.Ui.Output("Job start successful")
		if periodic && !paramjob {
			loc, err := job.Periodic.GetLocation()
			if err == nil {
				now := time.Now().In(loc)
				next, err := job.Periodic.Next(now)
				if err != nil {
					c.Ui.Error(fmt.Sprintf("Error determining next launch time: %v", err))
				} else {
					c.Ui.Output(fmt.Sprintf("Approximate next launch time: %s (%s from now)",
						formatTime(next), formatTimeDifference(now, next, time.Second)))
				}
			}
		} else if !paramjob {
			c.Ui.Output("Evaluation ID: " + resp.EvalID)
		}

		return 0
	}

	mon := newMonitor(c.Ui, client, length)
	return mon.monitor(resp.EvalID)
}
Repository: hashicorp/nomad
File: command/job_start.go (Go)

Code before:
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1

package command

import (
	"fmt"
	"os"
	"strings"
	"sync"

	"github.com/hashicorp/nomad/api"
	"github.com/hashicorp/nomad/api/contexts"
	"github.com/posener/complete"
)

type JobStartCommand struct {
	Meta
	versionSelected uint64
}

func (c *JobStartCommand) Help() string {
	helpText := `
Usage: nomad job start [options] <job>
Alias: nomad start

  Start an existing stopped job. This command is used to start a previously stopped job's
  most recent version. Upon successful start, an interactive
  monitor session will start to display log lines as the job starts its
  allocations based on its most recent version. It is safe to exit the monitor
  early using ctrl+c.

  When ACLs are enabled, this command requires a token with the 'submit-job'
  and 'read-job' capabilities for the job's namespace. The 'list-jobs'
  capability is required to run the command with job prefixes instead of exact
  job IDs.

General Options:

  ` + generalOptionsUsage(usageOptsDefault) + `

Start Options:

  -detach
    Return immediately instead of entering monitor mode. After the
    job start command is submitted, a new evaluation ID is printed to the

Review comment (suggestion):
It looks like we don't have any clue here to the user that they can use more than one job ID, or that if they do they all need to be in the same namespace.

Code after:
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1

package command

import (
	"fmt"
	"strings"
	"time"

	"github.com/hashicorp/nomad/api/contexts"
	"github.com/posener/complete"
)

type JobStartCommand struct {
	Meta
}

func (c *JobStartCommand) Help() string {
	helpText := `
Usage: nomad job start [options] <job>
Alias: nomad start

 Starts a stopped job. The job must be currently registered. Nomad will create a
 new version of the job based on its most recent version. Upon successful start,
 Nomad will enter an interactive monitor session. This is useful to watch
 Nomad's internals make scheduling decisions and place the submitted work onto
 nodes. The monitor will end once job placement is done. It is safe to exit the
 monitor early using ctrl+c.

 When ACLs are enabled, this command requires a token with the 'submit-job'
 capability for the job's namespace.

General Options:

 ` + generalOptionsUsage(usageOptsDefault) + `

Start Options:

 -detach
   Return immediately instead of entering monitor mode. After the
   job start command is submitted, a new evaluation ID is printed to the
   screen, which can be used to examine the evaluation using the eval-status
   command.

 -verbose
Repository: hashicorp/nomad
File: nomad/keyring_endpoint.go (Go)

Code before:
	if args.KeyID == "" {
		return fmt.Errorf("root key ID is required")
	}

	// lookup any existing key and validate the delete
	var index uint64
	snap, err := k.srv.fsm.State().Snapshot()
	if err != nil {
		return err
	}
	ws := memdb.NewWatchSet()
	rootKey, err := snap.RootKeyByID(ws, args.KeyID)
	if err != nil {
		return err
	}
	if rootKey != nil && rootKey.IsActive() {
		return fmt.Errorf("active root key cannot be deleted - call rotate first")
	}

	// make sure the key was used to encrypt an existing variable
	rootKeyInUse, err := snap.IsRootKeyInUse(args.KeyID)
	if err != nil {
		return err
	}
	if rootKeyInUse && !args.Force {
		return fmt.Errorf("root key in use, cannot delete")
	}

	_, index, err = k.srv.raftApply(structs.WrappedRootKeysDeleteRequestType, args)
	if err != nil {
		return err
	}

	// remove the key from the keyring too
	k.encrypter.RemoveKey(args.KeyID)

	reply.Index = index
	return nil
}

// ListPublic signing keys used for workload identities. This RPC is used to
// back a JWKS endpoint.
//
// Unauthenticated because public keys are not sensitive.
func (k *Keyring) ListPublic(args *structs.GenericRequest, reply *structs.KeyringListPublicResponse) error {

	// JWKS is a public endpoint: intentionally ignore auth errors and only
	// authenticate to measure rate metrics.
	k.srv.Authenticate(k.ctx, args)
	if done, err := k.srv.forward("Keyring.ListPublic", args, args, reply); done {
		return err

Review comment (suggestion):
There is no formatting, so we could use the below (the suggestion won't compile as the file also needs the new import):
```suggestion
		return errors.New("root key in use, cannot delete")
```

Code after:

	if args.KeyID == "" {
		return fmt.Errorf("root key ID is required")
	}

	// lookup any existing key and validate the delete
	var index uint64
	snap, err := k.srv.fsm.State().Snapshot()
	if err != nil {
		return err
	}
	ws := memdb.NewWatchSet()
	rootKey, err := snap.RootKeyByID(ws, args.KeyID)
	if err != nil {
		return err
	}

	if rootKey == nil {
		return errors.New("root key not found")
	}

	if rootKey != nil && rootKey.IsActive() {
		return fmt.Errorf("active root key cannot be deleted - call rotate first")
	}

	// make sure the key was used to encrypt an existing variable
	rootKeyInUse, err := snap.IsRootKeyInUse(args.KeyID)
	if err != nil {
		return err
	}
	if rootKeyInUse && !args.Force {
		return errors.New("root key in use, cannot delete")
	}

	_, index, err = k.srv.raftApply(structs.WrappedRootKeysDeleteRequestType, args)
	if err != nil {
		return err
	}

	// remove the key from the keyring too
	k.encrypter.RemoveKey(args.KeyID)

	reply.Index = index
	return nil
}

// ListPublic signing keys used for workload identities. This RPC is used to
// back a JWKS endpoint.
//
// Unauthenticated because public keys are not sensitive.
func (k *Keyring) ListPublic(args *structs.GenericRequest, reply *structs.KeyringListPublicResponse) error {
Repository: hashicorp/nomad
File: scheduler/numa_ce.go (Go)

Code before:
	"github.com/hashicorp/nomad/helper"
	"github.com/hashicorp/nomad/nomad/structs"
)

type coreSelector struct {
	topology       *numalib.Topology
	availableCores *idset.Set[hw.CoreID]
	shuffle        func([]numalib.Core)
}

// Select returns a set of CoreIDs that satisfy the requested core reservations,
// as well as the amount of CPU bandwidth represented by those specific cores.
//
// NUMA preference is available in ent only.
func (cs *coreSelector) Select(ask *structs.Resources) ([]uint16, hw.MHz) {
	cores := cs.availableCores.Slice()[0:ask.Cores]
	mhz := hw.MHz(0)
	sortedTopologyCores := make([]numalib.Core, len(cs.topology.Cores))
	copy(sortedTopologyCores, cs.topology.Cores)
	slices.SortFunc(sortedTopologyCores, func(a, b numalib.Core) int { return cmp.Compare(a.ID, b.ID) })
	for _, core := range cores {
		if i, found := slices.BinarySearchFunc(sortedTopologyCores, core, func(c numalib.Core, id hw.CoreID) int { return cmp.Compare(c.ID, id) }); found {
			mhz += cs.topology.Cores[i].MHz()
		}
	}
	ids := helper.ConvertSlice(cores, func(id hw.CoreID) uint16 { return uint16(id) })
	return ids, mhz
}

// randomize the cores so we can at least try to mitigate PFNR problems
func randomizeCores(cores []numalib.Core) {
	rand.Shuffle(len(cores), func(x, y int) {
		cores[x], cores[y] = cores[y], cores[x]
	})
}


Review comment (suggestion):
Instead of going back over the `cores` slice to pull out the ids, could they be collected in the search above? It saves an additional loop over that slice. 

Code after:
	"github.com/hashicorp/nomad/nomad/structs"
)

type coreSelector struct {
	topology       *numalib.Topology
	availableCores *idset.Set[hw.CoreID]
	shuffle        func([]numalib.Core)
}

// Select returns a set of CoreIDs that satisfy the requested core reservations,
// as well as the amount of CPU bandwidth represented by those specific cores.
//
// NUMA preference is available in ent only.
func (cs *coreSelector) Select(ask *structs.Resources) ([]uint16, hw.MHz) {
	cores := cs.availableCores.Slice()[0:ask.Cores]
	mhz := hw.MHz(0)
	ids := make([]uint16, 0, ask.Cores)
	sortedTopologyCores := make([]numalib.Core, len(cs.topology.Cores))
	copy(sortedTopologyCores, cs.topology.Cores)
	slices.SortFunc(sortedTopologyCores, func(a, b numalib.Core) int { return cmp.Compare(a.ID, b.ID) })
	for _, core := range cores {
		if i, found := slices.BinarySearchFunc(sortedTopologyCores, core, func(c numalib.Core, id hw.CoreID) int { return cmp.Compare(c.ID, id) }); found {
			mhz += cs.topology.Cores[i].MHz()
			ids = append(ids, uint16(cs.topology.Cores[i].ID))
		}
	}
	return ids, mhz
}

// randomize the cores so we can at least try to mitigate PFNR problems
func randomizeCores(cores []numalib.Core) {
	rand.Shuffle(len(cores), func(x, y int) {
		cores[x], cores[y] = cores[y], cores[x]
	})
}
Repository: hashicorp/nomad
File: nomad/host_volume_endpoint.go (Go)

Code before:
	}
	constraints := []*structs.Constraint{{
		LTarget: fmt.Sprintf("${attr.plugins.host_volume.%s.version}", vol.PluginID),
		Operand: "is_set",
	}}
	constraints = append(constraints, vol.Constraints...)
	checker = scheduler.NewConstraintChecker(ctx, constraints)

	var (
		filteredByExisting    int
		filteredByGovernance  int
		filteredByFeasibility int
	)

	for {
		raw := iter.Next()
		if raw == nil {
			break
		}
		candidate := raw.(*structs.Node)

		// note: this is a race if multiple users create volumes of the same
		// name concurrently, but we can't completely solve it on the server
		// because we haven't yet written to state. The client will reject
		// requests to create/register a volume with the same name with a
		// different ID.
		if snap.NodeHasHostVolume(candidate.ID, vol.Name) {
			filteredByExisting++
			continue
		}

		if !poolFilterFn(candidate.NodePool) {
			filteredByGovernance++
			continue
		}

		if checker != nil {
			if ok := checker.Feasible(candidate); !ok {
				filteredByFeasibility++
				continue
			}
		}

		vol.NodeID = candidate.ID
		vol.NodePool = candidate.NodePool
		return candidate, nil

	}

	return nil, fmt.Errorf(
		"no node meets constraints: %d nodes had existing volume, %d nodes filtered by node pool governance, %d nodes were infeasible",

Review comment (suggestion):
```suggestion
		// because we haven't yet written to state. The client single-threads
		// requests by volume name, so will reject requests to create/register
		// a volume with the same name but a different ID.
```

or something therabouts.

if you want to get real specific, this happens here: https://github.com/hashicorp/nomad/blob/49c147b/client/hostvolumemanager/host_volumes.go#L99-L103

Code after:
	}
	constraints := []*structs.Constraint{{
		LTarget: fmt.Sprintf("${attr.plugins.host_volume.%s.version}", vol.PluginID),
		Operand: "is_set",
	}}
	constraints = append(constraints, vol.Constraints...)
	checker = scheduler.NewConstraintChecker(ctx, constraints)

	var (
		filteredByExisting    int
		filteredByGovernance  int
		filteredByFeasibility int
	)

	for {
		raw := iter.Next()
		if raw == nil {
			break
		}
		candidate := raw.(*structs.Node)

		// note: this is a race if multiple users create volumes of the same
		// name concurrently, but we can't completely solve it on the server
		// because we haven't yet written to state. The client single-threads
		// requests by volume name, so will reject requests to create/register a
		// volume with the same name but a different ID.
		if snap.NodeHasHostVolume(candidate.ID, vol.Name) {
			filteredByExisting++
			continue
		}

		if !poolFilterFn(candidate.NodePool) {
			filteredByGovernance++
			continue
		}

		if checker != nil {
			if ok := checker.Feasible(candidate); !ok {
				filteredByFeasibility++
				continue
			}
		}

		vol.NodeID = candidate.ID
		vol.NodePool = candidate.NodePool
		return candidate, nil

	}

	return nil, fmt.Errorf(
		"no node meets constraints: %d nodes had existing volume, %d nodes filtered by node pool governance, %d nodes were infeasible",
Repository: hashicorp/nomad
File: enos/modules/drain_nodes/scripts/drain.sh (Shell)

Code before:
#!/usr/bin/env bash
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1

set -euo pipefail

error_exit() {
    printf 'Error: %s' "${1}"
    exit 1
}

DRAIN_DEADLINE="5s"

nodes=$(nomad node status -json | jq -r "[.[] | select(.Status == \"ready\") | .ID] | sort | .[:${NODES_TO_DRAIN}] | join(\" \")"  )

for node in $nodes; do
    echo "Drainning the node $node"
    
    nomad node drain --enable --deadline "$DRAIN_DEADLINE" "$node" \
      || error_exit "Failed to drain node $node"

    allocs=$(nomad alloc status -json | jq --arg node "$node" '[.[] | select(.NodeID == $node and .ClientStatus == "running")] | length')
    if [ $? -ne 0 ]; then
        error_exit "Allocs still running on $node"
    fi

    nomad node drain --disable  "$node" \
      || error_exit "Failed to disable drain for node $node"
    
    nomad node eligibility -enable  "$node" \
      || error_exit "Failed to set node $node back to eligible"
done


Review comment (suggestion):
```suggestion
    echo "Draining the node $node"
```

Code after:
#!/usr/bin/env bash
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1

set -euo pipefail

error_exit() {
    printf 'Error: %s' "${1}"
    exit 1
}

DRAIN_DEADLINE="5s"

nodes=$(nomad node status -json | jq -r "[.[] | select(.Status == \"ready\") | .ID] | sort | .[:${NODES_TO_DRAIN}] | join(\" \")"  )

for node in $nodes; do
    echo "Draining the node $node"
    
    nomad node drain --enable --deadline "$DRAIN_DEADLINE" "$node" \
      || error_exit "Failed to drain node $node"

    allocs=$(nomad alloc status -json | jq --arg node "$node" '[.[] | select(.NodeID == $node and .ClientStatus == "running")] | length')
    if [ $? -ne 0 ]; then
        error_exit "Allocs still running on $node"
    fi

    nomad node drain --disable  "$node" \
      || error_exit "Failed to disable drain for node $node"
done
Repository: hashicorp/nomad
File: enos/modules/drain_nodes/scripts/drain.sh (Shell)

Code before:

error_exit() {
    printf 'Error: %s' "${1}"
    exit 1
}

DRAIN_DEADLINE="5s"

nodes=$(nomad node status -json | jq -r "[.[] | select(.Status == \"ready\") | .ID] | sort | .[:${NODES_TO_DRAIN}] | join(\" \")"  )

for node in $nodes; do
    echo "Drainning the node $node"
    
    nomad node drain --enable --deadline "$DRAIN_DEADLINE" "$node" \
      || error_exit "Failed to drain node $node"

    allocs=$(nomad alloc status -json | jq --arg node "$node" '[.[] | select(.NodeID == $node and .ClientStatus == "running")] | length')
    if [ $? -ne 0 ]; then
        error_exit "Allocs still running on $node"
    fi

    nomad node drain --disable  "$node" \
      || error_exit "Failed to disable drain for node $node"
    
    nomad node eligibility -enable  "$node" \
      || error_exit "Failed to set node $node back to eligible"
done


Review comment (suggestion):
We're not using [--keep-ineligible](https://developer.hashicorp.com/nomad/docs/commands/node/drain#keep-ineligible) so we shouldn't need the last step once we disable draining.

Code after:
#!/usr/bin/env bash
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1

set -euo pipefail

error_exit() {
    printf 'Error: %s' "${1}"
    exit 1
}

DRAIN_DEADLINE="5s"

nodes=$(nomad node status -json | jq -r "[.[] | select(.Status == \"ready\") | .ID] | sort | .[:${NODES_TO_DRAIN}] | join(\" \")"  )

for node in $nodes; do
    echo "Draining the node $node"
    
    nomad node drain --enable --deadline "$DRAIN_DEADLINE" "$node" \
      || error_exit "Failed to drain node $node"

    allocs=$(nomad alloc status -json | jq --arg node "$node" '[.[] | select(.NodeID == $node and .ClientStatus == "running")] | length')
    if [ $? -ne 0 ]; then
        error_exit "Allocs still running on $node"
    fi

    nomad node drain --disable  "$node" \
      || error_exit "Failed to disable drain for node $node"
done
Repository: hashicorp/nomad
File: command/agent/config.go (Go)

Code before:
	} else if b.TLSConfig != nil {
		result.TLSConfig = result.TLSConfig.Merge(b.TLSConfig)
	}

	// Apply the client config
	if result.Client == nil && b.Client != nil {
		client := *b.Client
		result.Client = &client
	} else if b.Client != nil {
		result.Client = result.Client.Merge(b.Client)
	}

	// Apply the server config
	if result.Server == nil && b.Server != nil {
		server := *b.Server
		result.Server = &server
	} else if b.Server != nil {
		result.Server = result.Server.Merge(b.Server)
	}

	// Apply the rpc mux config
	if result.RPC == nil && b.RPC != nil {
		rpcMux := *b.RPC
		result.RPC = &rpcMux
	}

	// Apply the acl config
	if result.ACL == nil && b.ACL != nil {
		server := *b.ACL
		result.ACL = &server
	} else if b.ACL != nil {
		result.ACL = result.ACL.Merge(b.ACL)
	}

	// Apply the Audit config
	if result.Audit == nil && b.Audit != nil {
		audit := *b.Audit
		result.Audit = &audit
	} else if b.ACL != nil {
		result.Audit = result.Audit.Merge(b.Audit)
	}

	// Apply the ports config
	if result.Ports == nil && b.Ports != nil {
		ports := *b.Ports
		result.Ports = &ports
	} else if b.Ports != nil {
		result.Ports = result.Ports.Merge(b.Ports)
	}

	// Apply the address config

Review comment (suggestion):
This doesn't merge the configurations, it overwrites them entirely. So if you have two files:

```hcl
rpc {
  accept_backlog = 200
}
```

```hcl
rpc {
  keep_alive_interval = "5s"
}
```

Your resulting configuration struct is:

```go
&RPCConfig{
	AcceptBacklog: 0,
	KeepAliveInterval: 5000000000,
	KeepAliveIntervalHCL: "5s",
	ConnectionWriteTimeout: 0,
	ConnectionWriteTimeoutHCL: "",
	StreamOpenTimeout: 0,
	StreamOpenTimeoutHCL: "",
	StreamCloseTimeout: 0,
	StreamCloseTimeoutHCL: "",
}
```



Code after:
	}
	if b.LogRotateBytes != 0 {
		result.LogRotateBytes = b.LogRotateBytes
	}
	if b.LogRotateMaxFiles != 0 {
		result.LogRotateMaxFiles = b.LogRotateMaxFiles
	}
	if b.BindAddr != "" {
		result.BindAddr = b.BindAddr
	}
	if b.EnableDebug {
		result.EnableDebug = true
	}
	if b.LeaveOnInt {
		result.LeaveOnInt = true
	}
	if b.LeaveOnTerm {
		result.LeaveOnTerm = true
	}
	if b.EnableSyslog {
		result.EnableSyslog = true
	}
	if b.SyslogFacility != "" {
		result.SyslogFacility = b.SyslogFacility
	}
	if b.DisableUpdateCheck != nil {
		result.DisableUpdateCheck = pointer.Of(*b.DisableUpdateCheck)
	}
	if b.DisableAnonymousSignature {
		result.DisableAnonymousSignature = true
	}

	// Apply the telemetry config
	if result.Telemetry == nil && b.Telemetry != nil {
		telemetry := *b.Telemetry
		result.Telemetry = &telemetry
	} else if b.Telemetry != nil {
		result.Telemetry = result.Telemetry.Merge(b.Telemetry)
	}

	// Apply the Reporting Config
	if result.Reporting == nil && b.Reporting != nil {
		result.Reporting = b.Reporting.Copy()
	} else if b.Reporting != nil {
		result.Reporting = result.Reporting.Merge(b.Reporting)
	}

	// Apply the TLS Config
	if result.TLSConfig == nil && b.TLSConfig != nil {
		result.TLSConfig = b.TLSConfig.Copy()
	} else if b.TLSConfig != nil {
Repository: hashicorp/nomad
File: nomad/rpc.go (Go)

Code before:
		})
	}

	return &r
}

// RPCContext provides metadata about the RPC connection.
type RPCContext struct {
	// Conn exposes the raw connection.
	Conn net.Conn

	// Session exposes the multiplexed connection session.
	Session *yamux.Session

	// TLS marks whether the RPC is over a TLS based connection
	TLS bool

	// VerifiedChains is is the Verified certificates presented by the incoming
	// connection.
	VerifiedChains [][]*x509.Certificate

	// NodeID marks the NodeID that initiated the connection.
	NodeID string

	// MuxConfig allowing to change default yamux configs value for advanced configuration
	YamuxConfig *yamux.Config
}

func (ctx *RPCContext) IsTLS() bool {
	if ctx == nil {
		return false
	}
	return ctx.TLS
}

// Certificate returns the first certificate available in the chain.
func (ctx *RPCContext) Certificate() *x509.Certificate {
	if ctx == nil || len(ctx.VerifiedChains) == 0 || len(ctx.VerifiedChains[0]) == 0 {
		return nil
	}

	return ctx.VerifiedChains[0][0]
}

// ValidateCertificateForName returns true if the RPC context certificate is valid
// for the given domain name.
func (ctx *RPCContext) ValidateCertificateForName(name string) error {
	if ctx == nil || !ctx.TLS {
		return nil
	}


Review comment (suggestion):
Nitpick:

```suggestion
	// SessionConfig allowing to change default yamux configs value for advanced configuration
	SessionConfig *yamux.Config
```

Code after:
		})
	}

	return &r
}

// RPCContext provides metadata about the RPC connection.
type RPCContext struct {
	// Conn exposes the raw connection.
	Conn net.Conn

	// Session exposes the multiplexed connection session.
	Session *yamux.Session

	// TLS marks whether the RPC is over a TLS based connection
	TLS bool

	// VerifiedChains is is the Verified certificates presented by the incoming
	// connection.
	VerifiedChains [][]*x509.Certificate

	// NodeID marks the NodeID that initiated the connection.
	NodeID string

	// SessionConfig allowing to change default yamux configs value for advanced configuration
	SessionConfig *yamux.Config
}

func (ctx *RPCContext) IsTLS() bool {
	if ctx == nil {
		return false
	}
	return ctx.TLS
}

// Certificate returns the first certificate available in the chain.
func (ctx *RPCContext) Certificate() *x509.Certificate {
	if ctx == nil || len(ctx.VerifiedChains) == 0 || len(ctx.VerifiedChains[0]) == 0 {
		return nil
	}

	return ctx.VerifiedChains[0][0]
}

// ValidateCertificateForName returns true if the RPC context certificate is valid
// for the given domain name.
func (ctx *RPCContext) ValidateCertificateForName(name string) error {
	if ctx == nil || !ctx.TLS {
		return nil
	}