1
0
mirror of https://github.com/juanfont/headscale.git synced 2026-02-07 20:04:00 +01:00

all: fix err113 and nilnil lint issues (batch 4)

- Add sentinel errors and use %w wrapping for err113 compliance
- Add nolint:nilnil comments for valid nil,nil returns in config
- Files modified: hscontrol/db/ip.go, node.go, text_serialiser.go,
  users.go, hscontrol/noise.go, hscontrol/tailsql.go,
  hscontrol/types/config.go, config_test.go

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Kristoffer Dalby 2026-02-06 07:24:16 +00:00
parent 6533ec9637
commit 71b1a43b6e
8 changed files with 40 additions and 17 deletions

View File

@ -17,7 +17,11 @@ import (
"tailscale.com/net/tsaddr"
)
var errGeneratedIPBytesInvalid = errors.New("generated ip bytes are invalid ip")
var (
errGeneratedIPBytesInvalid = errors.New("generated ip bytes are invalid ip")
errGeneratedIPNotInPrefix = errors.New("generated ip not in prefix")
errIPAllocatorNil = errors.New("ip allocator was nil")
)
// IPAllocator is a singleton responsible for allocating
// IP addresses for nodes and making sure the same
@ -251,7 +255,8 @@ func randomNext(pfx netip.Prefix) (netip.Addr, error) {
if !pfx.Contains(ip) {
return netip.Addr{}, fmt.Errorf(
"generated ip(%s) not in prefix(%s)",
"%w: ip(%s) not in prefix(%s)",
errGeneratedIPNotInPrefix,
ip.String(),
pfx.String(),
)
@ -283,7 +288,7 @@ func (db *HSDatabase) BackfillNodeIPs(i *IPAllocator) ([]string, error) {
err = db.Write(func(tx *gorm.DB) error {
if i == nil {
return errors.New("backfilling IPs: ip allocator was nil")
return fmt.Errorf("backfilling IPs: %w", errIPAllocatorNil)
}
log.Trace().Caller().Msgf("starting to backfill IPs")

View File

@ -29,6 +29,9 @@ const (
NodeGivenNameTrimSize = 2
)
// ErrNodeNameNotUnique is returned when a node name is not unique.
var ErrNodeNameNotUnique = errors.New("node name is not unique")
var invalidDNSRegex = regexp.MustCompile("[^a-z0-9-.]+")
var (
@ -300,7 +303,7 @@ func RenameNode(tx *gorm.DB,
}
if count > 0 {
return errors.New("name is not unique")
return ErrNodeNameNotUnique
}
if err := tx.Model(&types.Node{}).Where("id = ?", nodeID).Update("given_name", newName).Error; err != nil {

View File

@ -3,12 +3,19 @@ package db
import (
"context"
"encoding"
"errors"
"fmt"
"reflect"
"gorm.io/gorm/schema"
)
var (
errUnmarshalTextValue = errors.New("unmarshalling text value")
errUnsupportedType = errors.New("unsupported type")
errTextMarshalerOnly = errors.New("only encoding.TextMarshaler is supported")
)
// Got from https://github.com/xdg-go/strum/blob/main/types.go
var textUnmarshalerType = reflect.TypeFor[encoding.TextUnmarshaler]()
@ -49,7 +56,7 @@ func (TextSerialiser) Scan(ctx context.Context, field *schema.Field, dst reflect
case string:
bytes = []byte(v)
default:
return fmt.Errorf("unmarshalling text value: %#v", dbValue)
return fmt.Errorf("%w: %#v", errUnmarshalTextValue, dbValue)
}
if isTextUnmarshaler(fieldValue) {
@ -75,7 +82,7 @@ func (TextSerialiser) Scan(ctx context.Context, field *schema.Field, dst reflect
return nil
} else {
return fmt.Errorf("unsupported type: %T", fieldValue.Interface())
return fmt.Errorf("%w: %T", errUnsupportedType, fieldValue.Interface())
}
}
@ -99,6 +106,6 @@ func (TextSerialiser) Value(ctx context.Context, field *schema.Field, dst reflec
return string(b), nil
default:
return nil, fmt.Errorf("only encoding.TextMarshaler is supported, got %t", v)
return nil, fmt.Errorf("%w, got %T", errTextMarshalerOnly, v)
}
}

View File

@ -12,9 +12,11 @@ import (
)
var (
ErrUserExists = errors.New("user already exists")
ErrUserNotFound = errors.New("user not found")
ErrUserStillHasNodes = errors.New("user not empty: node(s) found")
ErrUserExists = errors.New("user already exists")
ErrUserNotFound = errors.New("user not found")
ErrUserStillHasNodes = errors.New("user not empty: node(s) found")
ErrUserWhereInvalidCount = errors.New("expect 0 or 1 where User structs")
ErrUserNotUnique = errors.New("expected exactly one user")
)
func (hsdb *HSDatabase) CreateUser(user types.User) (*types.User, error) {
@ -158,7 +160,7 @@ func (hsdb *HSDatabase) ListUsers(where ...*types.User) ([]types.User, error) {
// ListUsers gets all the existing users.
func ListUsers(tx *gorm.DB, where ...*types.User) ([]types.User, error) {
if len(where) > 1 {
return nil, fmt.Errorf("expect 0 or 1 where User structs, got %d", len(where))
return nil, fmt.Errorf("%w, got %d", ErrUserWhereInvalidCount, len(where))
}
var user *types.User
@ -189,7 +191,7 @@ func (hsdb *HSDatabase) GetUserByName(name string) (*types.User, error) {
}
if len(users) != 1 {
return nil, fmt.Errorf("expected exactly one user, found %d", len(users))
return nil, fmt.Errorf("%w, found %d", ErrUserNotUnique, len(users))
}
return &users[0], nil

View File

@ -19,6 +19,9 @@ import (
"tailscale.com/types/key"
)
// ErrUnsupportedClientVersion is returned when a client connects with an unsupported protocol version.
var ErrUnsupportedClientVersion = errors.New("unsupported client version")
const (
// ts2021UpgradePath is the path that the server listens on for the WebSockets upgrade.
ts2021UpgradePath = "/ts2021"
@ -117,7 +120,7 @@ func (h *Headscale) NoiseUpgradeHandler(
}
func unsupportedClientError(version tailcfg.CapabilityVersion) error {
return fmt.Errorf("unsupported client version: %s (%d)", capver.TailscaleVersion(version), version)
return fmt.Errorf("%w: %s (%d)", ErrUnsupportedClientVersion, capver.TailscaleVersion(version), version)
}
func (ns *noiseServer) earlyNoise(protocolVersion int, writer io.Writer) error {

View File

@ -13,6 +13,9 @@ import (
"tailscale.com/types/logger"
)
// ErrNoCertDomains is returned when no cert domains are available for HTTPS.
var ErrNoCertDomains = errors.New("no cert domains available for HTTPS")
func runTailSQLService(ctx context.Context, logf logger.Logf, stateDir, dbPath string) error {
opts := tailsql.Options{
Hostname: "tailsql-headscale",
@ -73,7 +76,7 @@ func runTailSQLService(ctx context.Context, logf logger.Logf, stateDir, dbPath s
// When serving TLS, add a redirect from HTTP on port 80 to HTTPS on 443.
certDomains := tsNode.CertDomains()
if len(certDomains) == 0 {
return errors.New("no cert domains available for HTTPS")
return ErrNoCertDomains
}
base := "https://" + certDomains[0]

View File

@ -845,7 +845,7 @@ func prefixV4() (*netip.Prefix, error) {
prefixV4Str := viper.GetString("prefixes.v4")
if prefixV4Str == "" {
return nil, nil
return nil, nil //nolint:nilnil // empty prefix is valid, not an error
}
prefixV4, err := netip.ParsePrefix(prefixV4Str)
@ -870,7 +870,7 @@ func prefixV6() (*netip.Prefix, error) {
prefixV6Str := viper.GetString("prefixes.v6")
if prefixV6Str == "" {
return nil, nil
return nil, nil //nolint:nilnil // empty prefix is valid, not an error
}
prefixV6, err := netip.ParsePrefix(prefixV6Str)

View File

@ -284,7 +284,7 @@ func TestReadConfigFromEnv(t *testing.T) {
assert.Equal(t, "100.64.0.0/10", viper.GetString("prefixes.v4"))
assert.False(t, viper.GetBool("database.sqlite.write_ahead_log"))
return nil, nil
return nil, nil //nolint:nilnil // test setup returns nil to indicate no expected value
},
want: nil,
},