endpoint

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jun 17, 2026 License: Apache-2.0 Imports: 22 Imported by: 0

Documentation

Overview

Package endpoint registers the `safedep endpoint` command tree, the CLI front-end for SafeDep Cloud's EndpointManagementService (Endpoint Hub). All verbs require control-plane credentials.

Index

Constants

View Source
const (
	ActivityTypeAll       activityType = "all"
	ActivityTypeGuard     activityType = "guard"
	ActivityTypeInventory activityType = "inventory"
)
View Source
const (
	VerdictMalicious  = "malicious"
	VerdictSuspicious = "suspicious"
	VerdictCooldown   = "cooldown"
	VerdictBlocked    = "blocked"
)

CLI-facing verdict names assigned to GuardEvent.Verdict. Untyped so they assign cleanly into the existing string field.

Variables

View Source
var ErrEndpointNotInDirectory = errors.New("endpoint not found in local directory; run `safedep endpoint list` first or pass a ULID")

Functions

func Register

func Register(root *cobra.Command, a *app.App)

Types

type AmbiguousRefError

type AmbiguousRefError struct {
	Ref        string
	Candidates []DirectoryEntry
}

func (*AmbiguousRefError) Error

func (e *AmbiguousRefError) Error() string

type Directory

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

func NewDirectory

func NewDirectory(store Store, now func() time.Time) *Directory

func NewDirectoryFromApp

func NewDirectoryFromApp(a *app.App) (*Directory, error)

NewDirectoryFromApp builds a directory backed by the per-profile KV.

func (*Directory) Lookup

func (d *Directory) Lookup(ctx context.Context, id string) (DirectoryEntry, bool)

Lookup returns the cached entry for an ID, or false.

func (*Directory) Resolve

func (d *Directory) Resolve(ctx context.Context, ref string) (string, error)

Resolve maps a CLI-supplied reference to an endpoint ID. Accepts a full ULID, a unique ULID prefix (like `git` short SHAs), or a cached hostname/identifier. Errors with AmbiguousRefError when the reference matches multiple cached endpoints.

func (*Directory) Upsert

func (d *Directory) Upsert(ctx context.Context, entries []DirectoryEntry) error

Upsert merges entries into the cached directory, stamping CachedAt for any entry whose CachedAt is zero.

type DirectoryEntry

type DirectoryEntry struct {
	ID         string    `json:"id"`
	Name       string    `json:"name,omitempty"`
	Hostname   string    `json:"hostname,omitempty"`
	LastSyncAt time.Time `json:"last_sync_at,omitempty"`
	CachedAt   time.Time `json:"cached_at"`
}

type EndpointGetter

type EndpointGetter interface {
	Get(ctx context.Context, in GetInput) (*GetResult, error)
}

type EndpointLister

type EndpointLister interface {
	List(ctx context.Context, in ListInput) (*ListResult, error)
}

type GetInput

type GetInput struct {
	EndpointID string
	Window     TimeWindow
}

type GetResult

type GetResult struct {
	ID             string
	Identifier     string
	Hostname       string
	OS             string
	Arch           string
	LastSync       time.Time
	PerToolVolumes []ToolEventVolume
	LastInvocation *InvocationContext // nil if absent
}

type GuardAction

type GuardAction string // CLI vocab; see Action* constants below.
const (
	ActionBlocked         GuardAction = "blocked"
	ActionCooldownBlocked GuardAction = "cooldown-blocked"
	ActionConfirmed       GuardAction = "confirmed"
	ActionTrusted         GuardAction = "trusted"
)

CLI-facing action names. These are the only valid GuardAction values the rest of the CLI should produce. Mapping to/from proto enums lives in mapPmgActions and pmgActionToCLI.

type GuardCooldown

type GuardCooldown struct {
	PublishDate      time.Time `json:"publish_date,omitempty"`
	CooldownDays     uint32    `json:"cooldown_days"`
	DaysSincePublish uint32    `json:"days_since_publish"`
	DaysRemaining    uint32    `json:"days_remaining"`
}

GuardCooldown is the CLI-side projection of PmgDependencyCooldown.

type GuardEvent

type GuardEvent struct {
	Timestamp   time.Time
	EndpointID  string
	Tool        string // outer header ToolName
	ToolVersion string // outer header ToolVersion
	Action      GuardAction
	// Verdict is the user-facing reason for a block: "malicious",
	// "suspicious", "cooldown", or "blocked". Empty for non-block actions.
	Verdict        string
	PackageName    string
	PackageVersion string
	Ecosystem      string
	InvocationID   string
	// Cooldown carries publish-date / days-remaining context for
	// COOLDOWN_BLOCKED events. Nil for any other verdict.
	Cooldown *GuardCooldown
	Raw      *controltowerv1.ListEndpointPackageGuardEventsResponse_PackageGuardEvent
}

type GuardEventLister

type GuardEventLister interface {
	ListGuardEvents(ctx context.Context, in GuardEventsInput) (*GuardEventsResult, error)
}

type GuardEventsInput

type GuardEventsInput struct {
	Window       TimeWindow
	EndpointIDs  []string
	Actions      []GuardAction
	InvocationID string
	PageSize     uint32
	PageToken    string
}

type GuardEventsResult

type GuardEventsResult struct {
	Events   []GuardEvent
	NextPage string
}

type InventoryEvent

type InventoryEvent struct {
	Timestamp    time.Time
	EndpointID   string
	Tool         string // outer header ToolName
	Kind         messagescontroltowerv1.InventoryItemKind
	ItemIdentity string // ItemObserved.ItemIdentity (dedup key)
	Name         string // ItemObserved.Name
	App          string // ItemObserved.App
	Scope        messagescontroltowerv1.InventoryScope
	ConfigPath   string
	Metadata     map[string]string
	InvocationID string
	// Raw exposes the original proto event so JSON output preserves
	// every field. Intentional v1 trade-off for the activity feed.
	Raw *controltowerv1.ListEndpointInventoryEventsResponse_InventoryEvent
}

type InventoryEventLister

type InventoryEventLister interface {
	ListInventoryEvents(ctx context.Context, in InventoryEventsInput) (*InventoryEventsResult, error)
}

type InventoryEventsInput

type InventoryEventsInput struct {
	Window       TimeWindow
	EndpointIDs  []string
	ItemKinds    []messagescontroltowerv1.InventoryItemKind
	Scope        *messagescontroltowerv1.InventoryScope
	InvocationID string
	PageSize     uint32
	PageToken    string
}

type InventoryEventsResult

type InventoryEventsResult struct {
	Events   []InventoryEvent
	NextPage string
}

type InvocationContext

type InvocationContext struct {
	Command    string
	WorkingDir string
	HasCI      bool
	HasAgent   bool
}

InvocationContext mirrors the fields carried on the proto's EndpointInvocationContext: WorkingDirectory, Command, plus presence flags for CI / agent context.

type ListEndpoint

type ListEndpoint struct {
	ID               string
	Identifier       string // EndpointIdentity.Identifier (human label; falls back to hostname server-side)
	Hostname         string // EndpointIdentity.Metadata.Hostname
	OS               string // displayOS(EndpointIdentity.Metadata.Os)
	Arch             string // displayArch(EndpointIdentity.Metadata.Arch)
	LastSync         time.Time
	Capabilities     []controltowerv1.EndpointCapability
	PMGBlockedEvents uint64
	PMGTotalEvents   uint64
	InventoryEvents  uint64
}

type ListInput

type ListInput struct {
	Window        TimeWindow
	Capabilities  []controltowerv1.EndpointCapability
	MinPMGBlocked uint64 // 0 = no filter
	PageSize      uint32
	PageToken     string
}

type ListResult

type ListResult struct {
	Endpoints []ListEndpoint
	NextPage  string
}

type Service

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

Service is the production implementation backed by a control-plane gRPC connection. Command code accepts the small interfaces above.

func NewService

func NewService(conn *grpc.ClientConn) *Service

func (*Service) Get

func (s *Service) Get(ctx context.Context, in GetInput) (*GetResult, error)

func (*Service) List

func (s *Service) List(ctx context.Context, in ListInput) (*ListResult, error)

func (*Service) ListGuardEvents

func (s *Service) ListGuardEvents(ctx context.Context, in GuardEventsInput) (*GuardEventsResult, error)

func (*Service) ListInventoryEvents

func (s *Service) ListInventoryEvents(ctx context.Context, in InventoryEventsInput) (*InventoryEventsResult, error)

func (*Service) Stats

func (s *Service) Stats(ctx context.Context, in StatsInput) (*StatsResult, error)

type StatsFetcher

type StatsFetcher interface {
	Stats(ctx context.Context, in StatsInput) (*StatsResult, error)
}

type StatsInput

type StatsInput struct{ Window TimeWindow }

type StatsResult

type StatsResult struct {
	TotalEndpoints   uint64
	ActiveEndpoints  uint64
	SilentEndpoints  uint64 // derived: total - active
	TotalEvents      uint64
	PMGBlockedEvents uint64
}

type Store

type Store interface {
	Get(ctx context.Context) (map[string]DirectoryEntry, error)
	Put(ctx context.Context, v map[string]DirectoryEntry) error
}

Store is the small persistence surface the Directory needs. The production implementation wraps app.ProfileKV. Tests pass an in-memory fake.

type TimeWindow

type TimeWindow struct {
	// Both zero means "let the server apply defaults" (omit time_range).
	Start, End time.Time
}

func WindowFromDuration

func WindowFromDuration(now time.Time, since time.Duration) TimeWindow

WindowFromDuration returns a trailing window of length `since` ending at `now`. A non-positive duration returns a zero TimeWindow, which toTimeRangePtr translates to "omit time_range" so the server applies its default window.

func (TimeWindow) Label

func (w TimeWindow) Label() string

Label renders the window as a short human label like "last 168h" so renders can show users which window produced the rows.

type ToolEventVolume

type ToolEventVolume struct {
	Tool  string
	Count uint64
}

Jump to

Keyboard shortcuts

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