Documentation
¶
Overview ¶
Package gitops is the on-disk desired-state tree: lib/ profiles, blueprint manifests, and the committed baseline. Config identity = the config `name` (which is the .mobileconfig filename, matching how the console names uploads).
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type BlueprintSpec ¶
type BlueprintSpec struct {
Name string `yaml:"name"`
ID string `yaml:"id,omitempty"`
Description string `yaml:"description,omitempty"`
Configurations []string `yaml:"configurations"`
Apps *[]string `yaml:"apps,omitempty"` // app names
Packages *[]string `yaml:"packages,omitempty"` // package names
Devices *[]string `yaml:"devices,omitempty"` // device serial numbers
Users *[]string `yaml:"users,omitempty"` // user emails (or managed Apple Accounts)
Groups *[]string `yaml:"groups,omitempty"` // user-group names
}
BlueprintSpec is the git desired-state for one blueprint: its identity plus the member collections it manages. Blueprint CRUD and membership writes landed in Apple Business API v2.0 (2026-04-14), so all six collections are API-writable (the users/groups/devices themselves stay API-read-only — only their blueprint membership is managed here).
Configurations keeps its original semantics: always managed, absent == empty. The five newer keys are OPTIONAL, with pointer-to-slice semantics:
nil — key absent (or explicit null) → collection UNMANAGED, never touched present — even `apps: []` → manage to that exact set (detaches gated --prune)
func (BlueprintSpec) Members ¶ added in v0.4.15
func (s BlueprintSpec) Members(collection string) ([]string, bool)
Members returns the manifest's member list for one collection key and whether the manifest MANAGES that collection. Configurations is always managed (the original Phase-1 semantics: an absent key means "attach nothing", not "unmanaged"); the other five are managed only when their key is present, so an omitted key can never cause a detach. An unknown key is unmanaged.
func (BlueprintSpec) WithMember ¶ added in v0.4.20
func (s BlueprintSpec) WithMember(collection, name string) (BlueprintSpec, bool)
WithMember returns the spec with name ADDED to one collection's member list (sorted, de-duplicated), and whether the addition was possible. It is additive on purpose: adopting a live member must never drop a member the operator declared in git but hasn't attached yet — that entry is a pending attach, and rewriting the list from live (what the imperative attach path does, where the tenant was just written) would silently discard the intent.
An UNMANAGED optional collection (nil key) is left untouched and ok=false is returned: writing the key would flip the collection to managed, which makes every OTHER live member of it a --prune detach candidate. Growing a manifest's managed surface is `seed --blueprint-membership`'s job, never a side effect of adopting one member.
type Tree ¶
type Tree struct {
Root string
LibDir string
StateFile string
BlueprintsDir string
ArchiveDir string
}
Tree is the on-disk desired-state layout rooted at <envDir>/gitops.
func (*Tree) LoadBlueprints ¶
func (t *Tree) LoadBlueprints() (map[string]BlueprintSpec, error)
LoadBlueprints reads blueprints/*.yml → blueprint name → spec. A malformed file is a hard error (so a typo can't silently drop a blueprint from the plan).
func (*Tree) LoadDesired ¶
LoadDesired reads lib/*.mobileconfig → name → content.
func (*Tree) RemoveConfig ¶
RemoveConfig deletes a profile from lib/ (used when a config was removed from ABM → the git file is pruned). A missing file is not an error (idempotent).
func (*Tree) WriteBlueprintSpec ¶
func (t *Tree) WriteBlueprintSpec(s BlueprintSpec) error
WriteBlueprintSpec marshals a spec to blueprints/<slug>.yml. The filename slug is derived from the name (falling back to the id when the name has no slug-safe characters), and collisions are disambiguated with a numeric suffix so two distinct blueprints whose names sanitize to the same slug never overwrite each other. Re-writing the same blueprint (matched by name) reuses its file.
func (*Tree) WriteConfig ¶
WriteConfig writes a profile into lib/ under the given name.
The name comes from the TENANT (it is the configuration's `name` attribute, echoed back by Apple), so it is untrusted input on a filesystem path. A console-created config called `../../id_rsa` would otherwise have `seed`, `pull` and a reconcile Pull write outside the workspace entirely. internal/archive has guarded this since the beginning; lib/ never did.