hostaccess

package
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 6, 2026 License: AGPL-3.0 Imports: 15 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrKnownHostNotFound      = errors.New("known host not found")
	ErrKnownHostConflict      = errors.New("known host already exists")
	ErrKnownHostFQDNImmutable = errors.New("known host fqdn is immutable; rename = delete + create")
	ErrDuplicateKnownHostID   = errors.New("duplicate known host id in reconcile request")
	ErrDuplicateKnownHostFQDN = errors.New("duplicate fqdn in reconcile request")
	ErrHostGroupNotFound      = errors.New("host group not found")
	ErrHostGroupConflict      = errors.New("host group name already exists")
	ErrSuggestionNotFound     = errors.New("ignored suggestion not found")
	ErrSuggestionConflict     = errors.New("suggestion already ignored")
	ErrReferenceNotFound      = errors.New("referenced entity not found")
	ErrGroupNameRequired      = errors.New("group name is required")
	ErrDuplicateGroupID       = errors.New("duplicate group id")
)
View Source
var ErrBadRequest = errors.New("bad request")

ErrBadRequest is a sentinel wrapping input-validation failures that handlers should map to HTTP 400.

Functions

func NormaliseFQDN

func NormaliseFQDN(raw string) string

NormaliseFQDN trims whitespace, lowercases, and strips a trailing dot.

func ValidateFQDN

func ValidateFQDN(s string) error

ValidateFQDN checks that s is a well-formed hostname per RFC 1123. It expects the input to already be lowercased/trimmed (NormaliseFQDN does this).

Types

type DesiredHostGroup

type DesiredHostGroup struct {
	ID          *HostGroupID
	Name        string
	Color       *string
	Description *string
	Icon        *string
	HostIDs     []KnownHostID
}

DesiredHostGroup is the caller-provided shape of a single host group inside a reconcile request. A nil ID marks a brand-new group; a non-nil ID must match an existing group or the reconcile fails with ErrHostGroupNotFound.

type DesiredKnownHost

type DesiredKnownHost struct {
	ID       *KnownHostID
	FQDN     string
	Icon     *string
	GroupIDs []HostGroupID
}

DesiredKnownHost is the caller-provided shape of a single known host inside a reconcile request. A nil ID marks a brand-new host; a non-nil ID must match an existing row. FQDN is immutable on updates — a mismatch returns ErrKnownHostFQDNImmutable. GroupIDs replaces the host's full group membership.

type HTTPHandler

type HTTPHandler struct {
	// contains filtered or unexported fields
}

func NewHTTPHandler

func NewHTTPHandler(service *Service, logger *slog.Logger) *HTTPHandler

type HostGroup

type HostGroup struct {
	ID          HostGroupID   `db:"id"`
	Name        string        `db:"name"`
	Color       *string       `db:"color"`
	Description *string       `db:"description"`
	Icon        *string       `db:"icon"`
	UpdatedAt   time.Time     `db:"updated_at"`
	CreatedAt   time.Time     `db:"created_at"`
	HostIDs     []KnownHostID `db:"-"`
}

func (HostGroup) SameDefinitionAs

func (g HostGroup) SameDefinitionAs(other HostGroup) bool

SameDefinitionAs reports whether two groups would produce identical rows in host_groups + host_group_members. Used by the reconciler to skip no-op updates and avoid spurious updated_at bumps.

type HostGroupDraft

type HostGroupDraft struct {
	Name        string
	Color       *string
	Description *string
	Icon        *string
	HostIDs     []KnownHostID
}

HostGroupDraft is the minimum shape needed to insert a new host_groups row plus its members in a single repository call.

type HostGroupID

type HostGroupID int64

func (HostGroupID) Int64

func (id HostGroupID) Int64() int64

func (HostGroupID) String

func (id HostGroupID) String() string

type IgnoredHostSuggestion

type IgnoredHostSuggestion struct {
	ID        int64     `db:"id"`
	FQDN      string    `db:"fqdn"`
	CreatedAt time.Time `db:"created_at"`
}

type KnownHost

type KnownHost struct {
	ID        KnownHostID `db:"id"`
	FQDN      string      `db:"fqdn"`
	Icon      *string     `db:"icon"`
	UpdatedAt time.Time   `db:"updated_at"`
	CreatedAt time.Time   `db:"created_at"`
}

type KnownHostDraft

type KnownHostDraft struct {
	FQDN     string
	Icon     *string
	GroupIDs []HostGroupID
}

KnownHostDraft is the minimum shape needed to insert a new known_hosts row.

type KnownHostID

type KnownHostID int64

func (KnownHostID) Int64

func (id KnownHostID) Int64() int64

func (KnownHostID) String

func (id KnownHostID) String() string

type KnownHostRef

type KnownHostRef struct {
	ID   KnownHostID
	FQDN string
	Icon *string
}

KnownHostRef is a lightweight reference returned inside group member lists.

type Observer

type Observer interface {
	OnHostAccessChanged(ctx context.Context)
}

Observer is implemented by any component that must react when host access configuration changes (e.g. policy.Service refreshing its cache).

type ReconcileHostGroupsInput

type ReconcileHostGroupsInput struct {
	Groups []DesiredHostGroup
}

ReconcileHostGroupsInput is the full desired image of host_groups that the caller wants the database to converge to.

type ReconcileKnownHostsInput

type ReconcileKnownHostsInput struct {
	Hosts []DesiredKnownHost
}

ReconcileKnownHostsInput is the full desired image of known_hosts that the caller wants the database to converge to.

type Repository

type Repository struct {
	// contains filtered or unexported fields
}

func NewRepository

func NewRepository(db *database.DB) *Repository

func (*Repository) AddIgnoredSuggestion

func (r *Repository) AddIgnoredSuggestion(ctx context.Context, fqdn string) (IgnoredHostSuggestion, error)

func (*Repository) CreateHostGroup

func (r *Repository) CreateHostGroup(ctx context.Context, draft HostGroupDraft) (HostGroupID, error)

CreateHostGroup inserts a new host group together with its members in a single transaction. Intended to be called from inside a reconcile flow that already opened a transaction; in that case WithinTx reuses it.

CAUTION: when several CreateHostGroup / UpdateHostGroup calls run in the same reconcile transaction, the host_groups.name unique index is checked at each statement. Two existing groups swapping names would therefore fail on the first UPDATE. The reconcile orchestrator deletes before updating before creating to side-step the common cases, but a true rename-swap still needs a two-phase rename-via-temp that is not implemented yet.

func (*Repository) CreateKnownHost

func (r *Repository) CreateKnownHost(ctx context.Context, draft KnownHostDraft) (KnownHostID, error)

CreateKnownHost inserts a single known host row. Translates unique-violation to ErrKnownHostConflict.

func (*Repository) DeleteHostGroup

func (r *Repository) DeleteHostGroup(ctx context.Context, id HostGroupID) error

func (*Repository) DeleteKnownHost

func (r *Repository) DeleteKnownHost(ctx context.Context, id KnownHostID) error

func (*Repository) DeleteUserData

func (r *Repository) DeleteUserData(ctx context.Context, userID auth.UserID) error

func (*Repository) EnsureUserSettings

func (r *Repository) EnsureUserSettings(ctx context.Context, userID auth.UserID) error

func (*Repository) GetAllUserDirectHostGrants

func (r *Repository) GetAllUserDirectHostGrants(ctx context.Context) ([]UserHostGrant, error)

func (*Repository) GetAllUserGroupHostGrants

func (r *Repository) GetAllUserGroupHostGrants(ctx context.Context) ([]UserHostGrant, error)

func (*Repository) GetAllUserHostSettings

func (r *Repository) GetAllUserHostSettings(ctx context.Context) ([]UserHostSetting, error)

func (*Repository) ListHostGroups

func (r *Repository) ListHostGroups(ctx context.Context) ([]HostGroup, error)

ListHostGroups returns every host group with its member host IDs. Members are loaded with a second query and joined in memory so a group with no members still appears in the result (a single LEFT JOIN with GROUP BY is possible but harder to map back to typed slices via sqlx).

func (*Repository) ListKnownHosts

func (r *Repository) ListKnownHosts(ctx context.Context) ([]KnownHost, error)

ListKnownHosts returns all known hosts ordered by ID.

func (*Repository) ListKnownHostsByIDs

func (r *Repository) ListKnownHostsByIDs(ctx context.Context, ids []KnownHostID) ([]KnownHost, error)

func (*Repository) RemoveIgnoredSuggestionByFQDN

func (r *Repository) RemoveIgnoredSuggestionByFQDN(ctx context.Context, fqdn string) error

func (*Repository) SetFullUserGrants

func (r *Repository) SetFullUserGrants(ctx context.Context, userID auth.UserID, bypass *bool, hostIDs []KnownHostID, groupIDs []HostGroupID) error

func (*Repository) SetKnownHostGroupMembership

func (r *Repository) SetKnownHostGroupMembership(ctx context.Context, hostID KnownHostID, groupIDs []HostGroupID) error

SetKnownHostGroupMembership replaces the full set of groups that hostID belongs to. It deletes all existing host_group_members rows for hostID then inserts one row per groupID. An unknown groupID is mapped to ErrReferenceNotFound.

func (*Repository) UpdateHostGroup

func (r *Repository) UpdateHostGroup(ctx context.Context, group HostGroup) error

UpdateHostGroup replaces a group's metadata and its member set. See CreateHostGroup for the rename-swap caveat.

func (*Repository) UpdateKnownHost

func (r *Repository) UpdateKnownHost(ctx context.Context, id KnownHostID, icon *string) (KnownHost, error)

type Service

type Service struct {
	// contains filtered or unexported fields
}

func NewService

func NewService(repo repository, tx transactor, logger *slog.Logger) *Service

func (*Service) AddIgnoredSuggestion

func (s *Service) AddIgnoredSuggestion(ctx context.Context, fqdn string) (IgnoredHostSuggestion, error)

func (*Service) AddUserHostAccessObserver

func (s *Service) AddUserHostAccessObserver(o Observer)

func (*Service) GetAllUserHostAccess

func (s *Service) GetAllUserHostAccess(ctx context.Context) ([]policy.UserHostAccess, error)

GetAllUserHostAccess implements the policy.HostAccessProvider interface.

func (*Service) ListHostGroups

func (s *Service) ListHostGroups(ctx context.Context) ([]HostGroup, error)

func (*Service) ListKnownHosts

func (s *Service) ListKnownHosts(ctx context.Context) ([]KnownHost, error)

ListKnownHosts returns all known hosts ordered by ID.

func (*Service) OnUserEvent

func (s *Service) OnUserEvent(ctx context.Context, event auth.UserEvent)

func (*Service) ReconcileHostGroups

func (s *Service) ReconcileHostGroups(ctx context.Context, in ReconcileHostGroupsInput) error

ReconcileHostGroups makes the database converge to the desired image of host_groups + members in a single transaction. Groups present in `in` with a non-nil ID are updated; groups with a nil ID are created; groups currently in the database whose ID is absent from `in` are deleted.

All referenced known-host IDs are validated up-front so the transaction can fail fast without partial work. Observers are notified once on success because group membership changes can shift effective per-user host access.

func (*Service) ReconcileKnownHosts

func (s *Service) ReconcileKnownHosts(ctx context.Context, in ReconcileKnownHostsInput) error

ReconcileKnownHosts makes the database converge to the desired image of known_hosts in a single transaction. Hosts present in `in` with a non-nil ID are updated (icon only); hosts with a nil ID are created; hosts currently in the database whose ID is absent from `in` are deleted.

Note: deleting a known host cascades to host_group_members and user_allowed_hosts (ON DELETE CASCADE — migration 000018 lines 48, 62), so a reconcile that drops hosts implicitly changes effective user host access. Observers are always notified on success.

func (*Service) RemoveIgnoredSuggestionByFQDN

func (s *Service) RemoveIgnoredSuggestionByFQDN(ctx context.Context, fqdn string) error

func (*Service) SetFullUserGrants

func (s *Service) SetFullUserGrants(ctx context.Context, userID auth.UserID, bypass *bool, hostIDs []KnownHostID, groupIDs []HostGroupID) error

type UserHostGrant

type UserHostGrant struct {
	UserID auth.UserID `db:"user_id"`
	FQDN   string      `db:"fqdn"`
}

UserHostGrant is a resolved (user, fqdn) pair from either direct or group grants.

type UserHostSetting

type UserHostSetting struct {
	UserID          auth.UserID `db:"user_id"`
	BypassAllowlist bool        `db:"bypass_host_allowlist"`
}

UserHostSetting is the per-user bypass flag from user_host_settings.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL