all: apply godoc [Name] link conventions across comments

Every Go-identifier reference in // and /* */ comments now uses
godoc's [Name] linking syntax so pkg.go.dev and `go doc` render
them as clickable cross-references. No behaviour change.

Pattern applied across the tree:
  In-package         [Foo], [Foo.Bar]
  Cross-package      [pkg.Foo], [pkg.Foo.Bar]
  Stdlib             [netip.Prefix], [errors.Is], [context.Context]
  Tailscale          [tailcfg.MapResponse], [tailcfg.Node.CapMap],
                     [tailcfg.NodeAttrSuggestExitNode]

Skip rules:
  - File:line refs left as plain text
  - HuJSON wire keys inside backtick raw strings untouched
  - ACL/policy syntax tokens (tag:foo, autogroup:self, ...) not Go
    symbols, left as plain text
  - JSON/OIDC wire keys, gorm tags, RFC IPv6 placeholders, markdown
    link tags, decorative dividers — all left as-is
This commit is contained in:
Kristoffer Dalby 2026-05-18 18:35:53 +00:00
parent 17236fd284
commit 4cca63155d
124 changed files with 1037 additions and 1011 deletions

View file

@ -28,7 +28,7 @@ var (
ErrAPIKeyInvalidGeneration = errors.New("generated API key failed validation")
)
// CreateAPIKey creates a new ApiKey in a user, and returns it.
// CreateAPIKey creates a new [types.APIKey] in a user, and returns it.
func (hsdb *HSDatabase) CreateAPIKey(
expiration *time.Time,
) (string, *types.APIKey, error) {
@ -84,7 +84,7 @@ func (hsdb *HSDatabase) CreateAPIKey(
return keyStr, &key, nil
}
// ListAPIKeys returns the list of ApiKeys for a user.
// ListAPIKeys returns the list of [types.APIKey] values for a user.
func (hsdb *HSDatabase) ListAPIKeys() ([]types.APIKey, error) {
keys := []types.APIKey{}
@ -96,7 +96,7 @@ func (hsdb *HSDatabase) ListAPIKeys() ([]types.APIKey, error) {
return keys, nil
}
// GetAPIKey returns a ApiKey for a given key.
// GetAPIKey returns a [types.APIKey] for a given key.
func (hsdb *HSDatabase) GetAPIKey(prefix string) (*types.APIKey, error) {
key := types.APIKey{}
if result := hsdb.DB.First(&key, "prefix = ?", prefix); result.Error != nil {
@ -106,7 +106,7 @@ func (hsdb *HSDatabase) GetAPIKey(prefix string) (*types.APIKey, error) {
return &key, nil
}
// GetAPIKeyByID returns a ApiKey for a given id.
// GetAPIKeyByID returns a [types.APIKey] for a given id.
func (hsdb *HSDatabase) GetAPIKeyByID(id uint64) (*types.APIKey, error) {
key := types.APIKey{}
if result := hsdb.DB.Find(&types.APIKey{ID: id}).First(&key); result.Error != nil {
@ -116,7 +116,7 @@ func (hsdb *HSDatabase) GetAPIKeyByID(id uint64) (*types.APIKey, error) {
return &key, nil
}
// DestroyAPIKey destroys a ApiKey. Returns error if the ApiKey
// DestroyAPIKey destroys a [types.APIKey]. Returns error if the [types.APIKey]
// does not exist.
func (hsdb *HSDatabase) DestroyAPIKey(key types.APIKey) error {
if result := hsdb.DB.Unscoped().Delete(key); result.Error != nil {
@ -126,7 +126,7 @@ func (hsdb *HSDatabase) DestroyAPIKey(key types.APIKey) error {
return nil
}
// ExpireAPIKey marks a ApiKey as expired.
// ExpireAPIKey marks a [types.APIKey] as expired.
func (hsdb *HSDatabase) ExpireAPIKey(key *types.APIKey) error {
err := hsdb.DB.Model(&key).Update("Expiration", time.Now()).Error
if err != nil {

View file

@ -17,8 +17,8 @@ const (
fifty = 50 * time.Millisecond
)
// TestEphemeralGarbageCollectorGoRoutineLeak is a test for a goroutine leak in EphemeralGarbageCollector().
// It creates a new EphemeralGarbageCollector, schedules several nodes for deletion with a short expiry,
// TestEphemeralGarbageCollectorGoRoutineLeak is a test for a goroutine leak in [EphemeralGarbageCollector].
// It creates a new [EphemeralGarbageCollector], schedules several nodes for deletion with a short expiry,
// and verifies that the nodes are deleted when the expiry time passes, and then
// for any leaked goroutines after the garbage collector is closed.
func TestEphemeralGarbageCollectorGoRoutineLeak(t *testing.T) {
@ -89,8 +89,8 @@ func TestEphemeralGarbageCollectorGoRoutineLeak(t *testing.T) {
t.Logf("Final number of goroutines: %d", runtime.NumGoroutine())
}
// TestEphemeralGarbageCollectorReschedule is a test for the rescheduling of nodes in EphemeralGarbageCollector().
// It creates a new EphemeralGarbageCollector, schedules a node for deletion with a longer expiry,
// TestEphemeralGarbageCollectorReschedule is a test for the rescheduling of nodes in [EphemeralGarbageCollector].
// It creates a new [EphemeralGarbageCollector], schedules a node for deletion with a longer expiry,
// and then reschedules it with a shorter expiry, and verifies that the node is deleted only once.
func TestEphemeralGarbageCollectorReschedule(t *testing.T) {
// Deletion tracking mechanism
@ -145,8 +145,8 @@ func TestEphemeralGarbageCollectorReschedule(t *testing.T) {
deleteMutex.Unlock()
}
// TestEphemeralGarbageCollectorCancelAndReschedule is a test for the cancellation and rescheduling of nodes in EphemeralGarbageCollector().
// It creates a new EphemeralGarbageCollector, schedules a node for deletion, cancels it, and then reschedules it,
// TestEphemeralGarbageCollectorCancelAndReschedule is a test for the cancellation and rescheduling of nodes in [EphemeralGarbageCollector].
// It creates a new [EphemeralGarbageCollector], schedules a node for deletion, cancels it, and then reschedules it,
// and verifies that the node is deleted only once.
func TestEphemeralGarbageCollectorCancelAndReschedule(t *testing.T) {
// Deletion tracking mechanism
@ -214,8 +214,8 @@ func TestEphemeralGarbageCollectorCancelAndReschedule(t *testing.T) {
deleteMutex.Unlock()
}
// TestEphemeralGarbageCollectorCloseBeforeTimerFires is a test for the closing of the EphemeralGarbageCollector before the timer fires.
// It creates a new EphemeralGarbageCollector, schedules a node for deletion, closes the GC, and verifies that the node is not deleted.
// TestEphemeralGarbageCollectorCloseBeforeTimerFires is a test for the closing of the [EphemeralGarbageCollector] before the timer fires.
// It creates a new [EphemeralGarbageCollector], schedules a node for deletion, closes the GC, and verifies that the node is not deleted.
func TestEphemeralGarbageCollectorCloseBeforeTimerFires(t *testing.T) {
// Deletion tracking
var (
@ -264,7 +264,7 @@ func TestEphemeralGarbageCollectorCloseBeforeTimerFires(t *testing.T) {
deleteMutex.Unlock()
}
// TestEphemeralGarbageCollectorScheduleAfterClose verifies that calling Schedule after Close
// TestEphemeralGarbageCollectorScheduleAfterClose verifies that calling [EphemeralGarbageCollector.Schedule] after [EphemeralGarbageCollector.Close]
// is a no-op and doesn't cause any panics, goroutine leaks, or other issues.
func TestEphemeralGarbageCollectorScheduleAfterClose(t *testing.T) {
// Count initial goroutines to check for leaks
@ -339,7 +339,7 @@ func TestEphemeralGarbageCollectorScheduleAfterClose(t *testing.T) {
}
// TestEphemeralGarbageCollectorConcurrentScheduleAndClose tests the behavior of the garbage collector
// when Schedule and Close are called concurrently from multiple goroutines.
// when [EphemeralGarbageCollector.Schedule] and [EphemeralGarbageCollector.Close] are called concurrently from multiple goroutines.
func TestEphemeralGarbageCollectorConcurrentScheduleAndClose(t *testing.T) {
// Count initial goroutines
initialGoroutines := runtime.NumGoroutine()

View file

@ -49,7 +49,7 @@ type IPAllocator struct {
usedIPs netipx.IPSetBuilder
}
// NewIPAllocator returns a new IPAllocator singleton which
// NewIPAllocator returns a new [IPAllocator] singleton which
// can be used to hand out unique IP addresses within the
// provided IPv4 and IPv6 prefix. It needs to be created
// when headscale starts and needs to finish its read
@ -272,7 +272,7 @@ func isTailscaleReservedIP(ip netip.Addr) bool {
}
// BackfillNodeIPs will take a database transaction, and
// iterate through all of the current nodes in headscale
// iterate through all of the current nodes ([types.Node]) in headscale
// and ensure it has IP addresses according to the current
// configuration.
// This means that if both IPv4 and IPv6 is set in the
@ -346,7 +346,6 @@ func (db *HSDatabase) BackfillNodeIPs(i *IPAllocator) ([]string, error) {
// Use Updates() with Select() to only update IP fields, avoiding overwriting
// other fields like Expiry. We need Select() because Updates() alone skips
// zero values, but we DO want to update IPv4/IPv6 to nil when removing them.
// See issue #2862.
err := tx.Model(node).Select("ipv4", "ipv6").Updates(node).Error
if err != nil {
return fmt.Errorf("saving node(%d) after adding IPs: %w", node.ID, err)

View file

@ -109,7 +109,7 @@ func (hsdb *HSDatabase) getNode(uid types.UserID, name string) (*types.Node, err
})
}
// getNode finds a Node by name and user and returns the Node struct.
// getNode finds a [types.Node] by name and user and returns the [types.Node] struct.
func getNode(tx *gorm.DB, uid types.UserID, name string) (*types.Node, error) {
nodes, err := ListNodesByUser(tx, uid)
if err != nil {
@ -129,7 +129,7 @@ func (hsdb *HSDatabase) GetNodeByID(id types.NodeID) (*types.Node, error) {
return GetNodeByID(hsdb.DB, id)
}
// GetNodeByID finds a Node by ID and returns the Node struct.
// GetNodeByID finds a [types.Node] by ID and returns the [types.Node] struct.
func GetNodeByID(tx *gorm.DB, id types.NodeID) (*types.Node, error) {
mach := types.Node{}
if result := tx.
@ -147,7 +147,7 @@ func (hsdb *HSDatabase) GetNodeByMachineKey(machineKey key.MachinePublic) (*type
return GetNodeByMachineKey(hsdb.DB, machineKey)
}
// GetNodeByMachineKey finds a Node by its MachineKey and returns the Node struct.
// GetNodeByMachineKey finds a [types.Node] by its [key.MachinePublic] and returns the [types.Node] struct.
func GetNodeByMachineKey(
tx *gorm.DB,
machineKey key.MachinePublic,
@ -168,7 +168,7 @@ func (hsdb *HSDatabase) GetNodeByNodeKey(nodeKey key.NodePublic) (*types.Node, e
return GetNodeByNodeKey(hsdb.DB, nodeKey)
}
// GetNodeByNodeKey finds a Node by its NodeKey and returns the Node struct.
// GetNodeByNodeKey finds a [types.Node] by its [key.NodePublic] and returns the [types.Node] struct.
func GetNodeByNodeKey(
tx *gorm.DB,
nodeKey key.NodePublic,
@ -199,7 +199,7 @@ func SetLastSeen(tx *gorm.DB, nodeID types.NodeID, lastSeen time.Time) error {
return tx.Model(&types.Node{}).Where("id = ?", nodeID).Update("last_seen", lastSeen).Error
}
// RenameNode takes a Node struct and a new GivenName for the nodes
// RenameNode takes a [types.Node] struct and a new [types.Node.GivenName] for the nodes
// and renames it. Validation should be done in the state layer before calling this function.
func RenameNode(tx *gorm.DB,
nodeID types.NodeID, newName string,
@ -245,7 +245,7 @@ func (hsdb *HSDatabase) DeleteNode(node *types.Node) error {
})
}
// DeleteNode deletes a Node from the database.
// DeleteNode deletes a [types.Node] from the database.
// Caller is responsible for notifying all of change.
func DeleteNode(tx *gorm.DB,
node *types.Node,
@ -259,7 +259,7 @@ func DeleteNode(tx *gorm.DB,
return nil
}
// DeleteEphemeralNode deletes a Node from the database, note that this method
// DeleteEphemeralNode deletes a [types.Node] from the database, note that this method
// will remove it straight, and not notify any changes or consider any routes.
// It is intended for Ephemeral nodes.
func (hsdb *HSDatabase) DeleteEphemeralNode(
@ -276,7 +276,7 @@ func (hsdb *HSDatabase) DeleteEphemeralNode(
}
// RegisterNodeForTest is used only for testing purposes to register a node directly in the database.
// Production code should use state.HandleNodeFromAuthPath or state.HandleNodeFromPreAuthKey.
// Production code should use [state.State.HandleNodeFromAuthPath] or [state.State.HandleNodeFromPreAuthKey].
func RegisterNodeForTest(tx *gorm.DB, node types.Node, ipv4 *netip.Addr, ipv6 *netip.Addr) (*types.Node, error) {
if !testing.Testing() {
panic("RegisterNodeForTest can only be called during tests")
@ -387,7 +387,7 @@ func NodeSetMachineKey(
// EphemeralGarbageCollector is a garbage collector that will delete nodes after
// a certain amount of time.
// It is used to delete ephemeral nodes that have disconnected and should be
// It is used to delete ephemeral nodes ([types.Node.IsEphemeral]) that have disconnected and should be
// cleaned up.
type EphemeralGarbageCollector struct {
mu sync.Mutex
@ -399,7 +399,7 @@ type EphemeralGarbageCollector struct {
cancelCh chan struct{}
}
// NewEphemeralGarbageCollector creates a new EphemeralGarbageCollector, it takes
// NewEphemeralGarbageCollector creates a new [EphemeralGarbageCollector], it takes
// a deleteFunc that will be called when a node is scheduled for deletion.
func NewEphemeralGarbageCollector(deleteFunc func(types.NodeID)) *EphemeralGarbageCollector {
return &EphemeralGarbageCollector{

View file

@ -31,7 +31,7 @@ func (hsdb *HSDatabase) GetPolicy() (*types.Policy, error) {
}
// GetPolicy returns the latest policy from the database.
// This standalone function can be used in contexts where HSDatabase is not available,
// This standalone function can be used in contexts where [HSDatabase] is not available,
// such as during migrations.
func GetPolicy(tx *gorm.DB) (*types.Policy, error) {
var p types.Policy
@ -55,7 +55,7 @@ func GetPolicy(tx *gorm.DB) (*types.Policy, error) {
// PolicyBytes loads policy configuration from file or database based on the configured mode.
// Returns nil if no policy is configured, which is valid.
// This standalone function can be used in contexts where HSDatabase is not available,
// This standalone function can be used in contexts where [HSDatabase] is not available,
// such as during migrations.
func PolicyBytes(tx *gorm.DB, cfg *types.Config) ([]byte, error) {
switch cfg.Policy.Mode {

View file

@ -40,7 +40,7 @@ const (
authKeyLength = 64
)
// CreatePreAuthKey creates a new PreAuthKey in a user, and returns it.
// CreatePreAuthKey creates a new [types.PreAuthKey] in a user, and returns it.
// The uid parameter can be nil for system-created tagged keys.
// For tagged keys, uid tracks "created by" (who created the key).
// For user-owned keys, uid tracks the node owner.
@ -158,7 +158,7 @@ func (hsdb *HSDatabase) ListPreAuthKeys() ([]types.PreAuthKey, error) {
return Read(hsdb.DB, ListPreAuthKeys)
}
// ListPreAuthKeys returns all PreAuthKeys in the database.
// ListPreAuthKeys returns all [types.PreAuthKey] values in the database.
func ListPreAuthKeys(tx *gorm.DB) ([]types.PreAuthKey, error) {
var keys []types.PreAuthKey
@ -170,7 +170,7 @@ func ListPreAuthKeys(tx *gorm.DB) ([]types.PreAuthKey, error) {
return keys, nil
}
// ListPreAuthKeysByUser returns all PreAuthKeys belonging to a specific user.
// ListPreAuthKeysByUser returns all [types.PreAuthKey] values belonging to a specific user.
func ListPreAuthKeysByUser(tx *gorm.DB, uid types.UserID) ([]types.PreAuthKey, error) {
var keys []types.PreAuthKey
@ -290,13 +290,13 @@ func (hsdb *HSDatabase) GetPreAuthKey(key string) (*types.PreAuthKey, error) {
return GetPreAuthKey(hsdb.DB, key)
}
// GetPreAuthKey returns a PreAuthKey for a given key. The caller is responsible
// GetPreAuthKey returns a [types.PreAuthKey] for a given key. The caller is responsible
// for checking if the key is usable (expired or used).
func GetPreAuthKey(tx *gorm.DB, key string) (*types.PreAuthKey, error) {
return findAuthKey(tx, key)
}
// DestroyPreAuthKey destroys a preauthkey. Returns error if the PreAuthKey
// DestroyPreAuthKey destroys a preauthkey. Returns error if the [types.PreAuthKey]
// does not exist. This also clears the auth_key_id on any nodes that reference
// this key.
func DestroyPreAuthKey(tx *gorm.DB, id uint64) error {
@ -331,10 +331,10 @@ func (hsdb *HSDatabase) DeletePreAuthKey(id uint64) error {
})
}
// UsePreAuthKey atomically marks a PreAuthKey as used. The UPDATE is
// UsePreAuthKey atomically marks a [types.PreAuthKey] as used. The UPDATE is
// guarded by `used = false` so two concurrent registrations racing for
// the same single-use key cannot both succeed: the first commits and
// the second returns PAKError("authkey already used"). Without the
// the second returns [types.PAKError]("authkey already used"). Without the
// guard the previous code (Update("used", true) with no WHERE) would
// silently let both transactions claim the key.
func UsePreAuthKey(tx *gorm.DB, k *types.PreAuthKey) error {
@ -354,7 +354,7 @@ func UsePreAuthKey(tx *gorm.DB, k *types.PreAuthKey) error {
return nil
}
// ExpirePreAuthKey marks a PreAuthKey as expired.
// ExpirePreAuthKey marks a [types.PreAuthKey] as expired.
func ExpirePreAuthKey(tx *gorm.DB, id uint64) error {
now := time.Now()
return tx.Model(&types.PreAuthKey{}).Where("id = ?", id).Update("expiration", now).Error

View file

@ -25,7 +25,7 @@ func (hsdb *HSDatabase) CreateUser(user types.User) (*types.User, error) {
})
}
// CreateUser creates a new User. Returns error if could not be created
// CreateUser creates a new [types.User]. Returns error if could not be created
// or another user already exists.
func CreateUser(tx *gorm.DB, user types.User) (*types.User, error) {
err := util.ValidateUsername(user.Name)
@ -47,7 +47,7 @@ func (hsdb *HSDatabase) DestroyUser(uid types.UserID) error {
})
}
// DestroyUser destroys a User. Returns error if the User does
// DestroyUser destroys a [types.User]. Returns error if the [types.User] does
// not exist or if there are user-owned nodes associated with it.
// Tagged nodes have user_id = NULL so they do not block deletion.
func DestroyUser(tx *gorm.DB, uid types.UserID) error {
@ -92,8 +92,8 @@ func (hsdb *HSDatabase) RenameUser(uid types.UserID, newName string) error {
var ErrCannotChangeOIDCUser = errors.New("cannot edit OIDC user")
// RenameUser renames a User. Returns error if the User does
// not exist or if another User exists with the new name.
// RenameUser renames a [types.User]. Returns error if the [types.User] does
// not exist or if another [types.User] exists with the new name.
func RenameUser(tx *gorm.DB, uid types.UserID, newName string) error {
var err error

View file

@ -84,7 +84,7 @@ func parseVersion(s string) (semver, error) {
}
// ensureDatabaseVersionTable creates the database_versions table if it
// does not already exist. Uses GORM AutoMigrate to handle dialect
// does not already exist. Uses [gorm.DB.AutoMigrate] to handle dialect
// differences between SQLite (datetime) and PostgreSQL (timestamp).
// This runs before gormigrate migrations.
func ensureDatabaseVersionTable(db *gorm.DB) error {