mgmt

package
v0.16.0 Latest Latest
Warning

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

Go to latest
Published: Apr 28, 2026 License: Apache-2.0 Imports: 15 Imported by: 0

Documentation

Overview

Package mgmt contains shared data types and serializers for sx management features: teams (interface types only — on-disk storage lives in the manifest package), identity resolution, usage events, and audit events.

Index

Constants

View Source
const (
	EventTeamCreated       = "team.created"
	EventTeamUpdated       = "team.updated"
	EventTeamDeleted       = "team.deleted"
	EventTeamMemberAdded   = "team.member_added"
	EventTeamMemberRemoved = "team.member_removed"
	EventTeamAdminSet      = "team.admin_set"
	EventTeamAdminUnset    = "team.admin_unset"
	EventTeamRepoAdded     = "team.repo_added"
	EventTeamRepoRemoved   = "team.repo_removed"
	EventAssetCreated      = "asset.created"
	EventAssetUpdated      = "asset.updated"
	EventAssetRemoved      = "asset.removed"
	EventAssetRenamed      = "asset.renamed"
	EventInstallSet        = "install.set"
	EventInstallCleared    = "install.cleared"
)

Audit event names. These mirror the set skills.new emits so dashboards and downstream consumers can treat the two streams interchangeably.

View Source
const (
	TargetTypeTeam         = "team"
	TargetTypeAsset        = "asset"
	TargetTypeInstallation = "installation"
)

Audit target type constants.

View Source
const AuditDirName = ".sx/audit"

AuditDirName is the directory under the vault root that holds monthly audit JSONL files.

View Source
const UsageDirName = ".sx/usage"

UsageDirName is the directory under the vault root that holds monthly usage JSONL files.

Variables

View Source
var ErrEmptyTeamName = errors.New("team name cannot be empty")

ErrEmptyTeamName is returned when a team name is blank or whitespace- only. Names are the primary key of teams in the manifest so an empty one would collide with any other empty-named team and hide from lookups.

View Source
var ErrIdentityNotSet = errors.New("identity not set: run 'git config --global user.email \"you@example.com\"'")

ErrIdentityNotSet is returned when no git email or fallback identity can be determined.

View Source
var ErrLastAdmin = errors.New("team would be left without an admin")

ErrLastAdmin is returned when a mutation would leave a team with zero admins, which would render the team permanently unmanageable.

View Source
var ErrTeamExists = errors.New("team already exists")

ErrTeamExists is returned when attempting to create a team that already exists.

View Source
var ErrTeamNotFound = errors.New("team not found")

ErrTeamNotFound is returned when a team lookup fails.

Functions

func AppendAuditEvent

func AppendAuditEvent(vaultRoot string, event AuditEvent) error

AppendAuditEvent appends an event to the monthly audit file for the event's timestamp. The parent directory is created if needed.

func AppendUsageEvents

func AppendUsageEvents(vaultRoot string, events []UsageEvent) error

AppendUsageEvents appends a batch of usage events to the monthly files for their timestamps. Events with a zero timestamp are stamped with the current UTC time. Events are grouped by month and written with one O_APPEND handle per month to minimize syscalls.

func NormalizeEmail

func NormalizeEmail(email string) string

NormalizeEmail lowercases and trims an email for comparison.

func ResetActorCache

func ResetActorCache()

ResetActorCache clears the actor cache. Exposed for tests.

Types

type Actor

type Actor struct {
	Email string
	Name  string

	// Synthetic is true when Email was derived from $USER@host instead of
	// a real git config value. Synthetic actors cannot pass mgmt
	// mutations because their identity can be spoofed by flipping $USER;
	// see RequireRealIdentity.
	Synthetic bool
}

Actor is a resolved caller identity used for audit, usage, and install targeting.

func CurrentGitActor

func CurrentGitActor(ctx context.Context, repoPath string) (Actor, error)

CurrentGitActor resolves the caller's identity via `git config user.email` (scoped to the given repoPath if non-empty, falling back to global git config). If git is unconfigured or unavailable, it tries to synthesize an identity from $USER and the hostname. Returns ErrIdentityNotSet only when every source fails.

func (Actor) RequireRealIdentity

func (a Actor) RequireRealIdentity() error

RequireRealIdentity returns ErrIdentityNotSet if the actor is synthetic. Call this at the top of any mgmt mutation helper that writes to shared vault state (teams, installations, scopes) — a synthetic identity is fine for reads but cannot be trusted as the authoritative actor behind a persisted change.

func (Actor) String

func (a Actor) String() string

String returns "name <email>" if both are set, just the email otherwise.

type ActorUsageCount

type ActorUsageCount struct {
	Actor     string
	TotalUses int
}

ActorUsageCount is the per-actor rollup in a UsageSummary.

type AssetUsageCount

type AssetUsageCount struct {
	AssetName    string
	AssetType    string
	TotalUses    int
	UniqueActors int
	LastUsed     time.Time
}

AssetUsageCount is the per-asset rollup in a UsageSummary.

type AuditEvent

type AuditEvent struct {
	Timestamp  time.Time      `json:"ts"`
	Actor      string         `json:"actor"`
	Event      string         `json:"event"`
	TargetType string         `json:"target_type"`
	Target     string         `json:"target"`
	Data       map[string]any `json:"data,omitempty"`
}

AuditEvent is a single row in .sx/audit/YYYY-MM.jsonl.

func QueryAuditEvents

func QueryAuditEvents(vaultRoot string, filter AuditFilter) ([]AuditEvent, error)

QueryAuditEvents reads all monthly files under .sx/audit and returns the events that match the filter, sorted newest first. A non-existent audit directory returns an empty slice, not an error.

type AuditFilter

type AuditFilter struct {
	Actor       string
	EventPrefix string
	Target      string
	Since       time.Time
	Until       time.Time
	Limit       int
}

AuditFilter narrows an audit query. Zero values mean "don't filter on that field". EventPrefix matches if the event string starts with the prefix (e.g. "team." matches every team event).

type Team

type Team struct {
	Name         string   `toml:"name"`
	Description  string   `toml:"description,omitempty"`
	Members      []string `toml:"members,omitempty"`
	Admins       []string `toml:"admins,omitempty"`
	Repositories []string `toml:"repositories,omitempty"`
}

Team is a named grouping of members, admins, and repositories. It is the unit of targeted installation for git and path vaults and the shape returned by the Vault interface's team-management methods.

func (*Team) IsAdmin

func (t *Team) IsAdmin(email string) bool

IsAdmin returns true if the given email is in the team's admin list. Comparison is case-insensitive.

func (*Team) IsMember

func (t *Team) IsMember(email string) bool

IsMember returns true if the given email is in the team's member list. Comparison is case-insensitive.

type UsageEvent

type UsageEvent struct {
	Timestamp    time.Time `json:"ts"`
	Actor        string    `json:"actor"`
	AssetName    string    `json:"asset_name"`
	AssetVersion string    `json:"asset_version"`
	AssetType    string    `json:"asset_type"`
}

UsageEvent is a single row in .sx/usage/YYYY-MM.jsonl. Timestamp and actor are normalized to UTC and lowercase respectively at append time.

func ReadUsageEvents

func ReadUsageEvents(vaultRoot string, filter UsageFilter) ([]UsageEvent, error)

ReadUsageEvents reads every event from the vault's usage directory, filtered by the given filter. Returned events are not sorted.

type UsageFilter

type UsageFilter struct {
	AssetName string
	AssetType string
	Actor     string
	Since     time.Time
	Until     time.Time
}

UsageFilter narrows a usage query.

type UsageSummary

type UsageSummary struct {
	TotalEvents int
	PerAsset    []AssetUsageCount
	PerActor    []ActorUsageCount
}

UsageSummary is the aggregated result of a usage query.

func SummarizeUsage

func SummarizeUsage(vaultRoot string, filter UsageFilter) (*UsageSummary, error)

SummarizeUsage computes per-asset and per-actor rollups over the matching events. The slices are returned sorted by TotalUses descending.

Jump to

Keyboard shortcuts

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