ab

package
v0.4.15 Latest Latest
Warning

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

Go to latest
Published: Jul 10, 2026 License: AGPL-3.0 Imports: 24 Imported by: 0

Documentation

Overview

Package ab is the Apple Business API client: ES256 client-assertion auth + typed read methods. Auth OMITS the JWT `kid` (verified live: a kid -> invalid_client).

Index

Constants

View Source
const (
	CollectionConfigurations = "configurations"
	CollectionApps           = "apps"
	CollectionPackages       = "packages"
	CollectionDevices        = "devices"
	CollectionUsers          = "users"
	CollectionGroups         = "groups"
)

Blueprint member collections, keyed by the manifest key used in gitops/blueprints/*.yml (see gitops.BlueprintSpec.Members).

Variables

BlueprintCollections lists the six member collections in manifest order.

Functions

func BlueprintRel added in v0.4.15

func BlueprintRel(collection string) string

BlueprintRel maps a manifest collection key to the blueprint relationship name (== member type). The empty key maps to "configurations" so plan items that predate the Collection field keep working; an unknown key returns "".

Types

type APIError

type APIError struct {
	Status int
	Body   string
}

APIError carries a non-2xx response.

func (*APIError) Error

func (e *APIError) Error() string

type Client

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

Client is a thin Apple Business API client (read methods for Phase 0).

func NewClient

func NewClient(cfg *config.Config) *Client

NewClient builds an Apple Business API client from the resolved config.

func (*Client) APIWrite

func (c *Client) APIWrite(method, path string, payload any) (int, []byte, error)

APIWrite issues an authenticated non-GET request with a JSON body (used by the gated `api` passthrough). A nil payload sends no body. It retries 401 (re-mint) and 429, never 5xx (a write may have partially applied).

func (*Client) AddBlueprintMembers

func (c *Client) AddBlueprintMembers(bpID, rel, memberType string, ids []string) error

AddBlueprintMembers / RemoveBlueprintMembers converge a blueprint relation via explicit per-member ops (correct whether Apple merges or replaces). Gated in the engine — not used by autonomous config-only apply.

func (*Client) AssignDevices added in v0.4.15

func (c *Client) AssignDevices(serverID string, deviceIDs []string) (string, error)

AssignDevices POSTs an ASSIGN_DEVICES activity moving deviceIDs (orgDevice ids) onto the MDM server. It returns the activity id for status polling (GetOrgDeviceActivity) — the assignment completes asynchronously.

func (*Client) AuditEvents

func (c *Client) AuditEvents(start, end string) ([]Resource, error)

AuditEvents returns audit events between the start and end timestamps (ISO 8601).

func (*Client) BlueprintRelationship

func (c *Client) BlueprintRelationship(id, rel string) ([]Resource, error)

BlueprintRelationship returns linkage IDs for a blueprint member relation.

func (*Client) CreateBlueprint added in v0.4.15

func (c *Client) CreateBlueprint(name, description string, members map[string][]string) (*Resource, error)

CreateBlueprint POSTs a new blueprint. description is optional (omitted when empty). members maps a relationship name (see BlueprintRel) to resolved ABM ids and is INLINED in the create request: live testing (2026-07-05, HANDOFF.md) showed Apple rejects a member-less create (`409 …MISSING_MEMBERS` / `MISSING_RESOURCES`), so a bare POST is only useful if Apple relaxes that — callers should inline what they can and surface the 409 verbatim otherwise. Post-create convergence still goes through Add/RemoveBlueprintMembers (relationships POST merges additively).

func (*Client) CreateConfiguration

func (c *Client) CreateConfiguration(name, xml string, platforms []string) (id, updated string, err error)

CreateConfiguration POSTs a CUSTOM_SETTING config with the raw .mobileconfig XML. It returns the new config's ID and its server-assigned updatedDateTime (parsed from the 201 body) so the caller can record an exact baseline with no extra GET.

func (*Client) CreateMDMServer added in v0.4.15

func (c *Client) CreateMDMServer(name, certName string, certPEM []byte, disown *bool) (*Resource, error)

CreateMDMServer POSTs a new MDM server with its push-certificate PEM. disown is optional (nil = omit, let Apple default enableMdmDisownFlag). The PEM is sent to Apple verbatim and never logged.

func (*Client) DeleteBlueprint added in v0.4.15

func (c *Client) DeleteBlueprint(id string) error

DeleteBlueprint deletes a blueprint by id.

func (*Client) DeleteConfiguration

func (c *Client) DeleteConfiguration(id string) error

DeleteConfiguration deletes a configuration by id.

func (*Client) DeleteMDMServer added in v0.4.15

func (c *Client) DeleteMDMServer(id string) error

DeleteMDMServer deletes an MDM server by id. Apple refuses (409) while devices are still assigned to it — that error is surfaced verbatim so the caller can tell the user to unassign first.

func (*Client) DeviceAppleCare added in v0.4.15

func (c *Client) DeviceAppleCare(id string) ([]Resource, error)

DeviceAppleCare returns an organization device's AppleCare coverage records.

func (*Client) DeviceAssignedServer added in v0.4.15

func (c *Client) DeviceAssignedServer(id string) (*Resource, error)

DeviceAssignedServer returns the MDM server an organization device is assigned to, or (nil, nil) when the device is unassigned (Apple answers 404).

func (*Client) FetchBlueprintMemberMaps added in v0.4.15

func (c *Client) FetchBlueprintMemberMaps(collections []string, progress func(string)) (nameByID, canonicalByAlias map[string]map[string]string, err error)

FetchBlueprintMemberMaps builds the id → display-name map for each requested member collection by listing that collection's tenant resources once (one paginated list per collection — fetch only the collections some manifest manages, or five full-tenant lists are wasted). Devices are keyed by serialNumber, users by email (falling back to managedAppleAccount, matching ResolveUser), apps/packages/user groups by name. "configurations" is skipped — the config map is ownership-scoped to the sync baseline and supplied by the caller — and a resource with no display name is omitted, so its id passes through membership lists as-is and is never planned for detach.

The second map resolves the ALIASES the imperative resolvers also accept — per collection, lowercased alias → canonical display name (devices: serial case variants; users: email AND managedAppleAccount, case-insensitive) — so a manifest entry written as an accepted alias can be canonicalized before the byte-exact membership diff. An alias claimed by more than one canonical name maps to "" (ambiguous — the caller must leave the manifest entry untouched).

func (*Client) FetchBlueprints

func (c *Client) FetchBlueprints(collections []string, nameByID map[string]map[string]string, progress func(string)) ([]LiveBlueprint, error)

FetchBlueprints lists all blueprints and resolves each one's membership to display names for the requested collections. "configurations" is always fetched (blueprint sync depends on it) whether or not it is listed; each other collection costs one relationship call per blueprint, so callers pass only the collections their manifests actually manage. nameByID maps collection key → member id → display name (see FetchBlueprintMemberMaps); an unresolved or unnamed id passes through as-is.

func (*Client) FetchCustomSettingDetail added in v0.4.9

func (c *Client) FetchCustomSettingDetail(id string) (LiveConfig, error)

FetchCustomSettingDetail returns one CUSTOM_SETTING configuration with profile XML.

func (*Client) FetchCustomSettings

func (c *Client) FetchCustomSettings() ([]LiveConfig, error)

FetchCustomSettings returns all CUSTOM_SETTING configs with their raw XML. Uses one list call with fields[] (incl. customSettingsValues) to avoid a GET per config; falls back to a per-config GET only if the list came back sparse.

func (*Client) FetchCustomSettingsMetadata added in v0.4.9

func (c *Client) FetchCustomSettingsMetadata(progress func(string)) ([]LiveConfig, error)

FetchCustomSettingsMetadata returns CUSTOM_SETTING configurations without requesting profile XML.

func (*Client) FetchCustomSettingsWithProgress added in v0.4.4

func (c *Client) FetchCustomSettingsWithProgress(progress func(string)) ([]LiveConfig, error)

FetchCustomSettingsWithProgress returns live CUSTOM_SETTING configurations while reporting long-running list and per-profile detail fetch progress through progress.

func (*Client) GetApp added in v0.4.15

func (c *Client) GetApp(id string) (*Resource, error)

GetApp fetches a single owned app (Apps & Books) by id.

func (*Client) GetBlueprint

func (c *Client) GetBlueprint(id string) (*Resource, error)

GetBlueprint fetches a single blueprint by ID.

func (*Client) GetConfiguration

func (c *Client) GetConfiguration(id string) (*Resource, error)

GetConfiguration fetches a single configuration by ID.

func (*Client) GetDevice added in v0.4.15

func (c *Client) GetDevice(id string) (*Resource, error)

GetDevice fetches a single organization device (orgDevice) by id.

func (*Client) GetMDMDevice added in v0.4.15

func (c *Client) GetMDMDevice(id string) (*Resource, error)

GetMDMDevice fetches a single built-in-MDM device by id.

func (*Client) GetMDMDeviceDetails added in v0.4.15

func (c *Client) GetMDMDeviceDetails(id string) (*Resource, error)

GetMDMDeviceDetails fetches a built-in-MDM device's last-reported posture (OS version, FileVault/firewall state, storage, lock/erase/lost-mode status).

func (*Client) GetMDMServer added in v0.4.15

func (c *Client) GetMDMServer(id string) (*Resource, error)

GetMDMServer fetches a single MDM server by id.

func (*Client) GetOrgDeviceActivity added in v0.4.15

func (c *Client) GetOrgDeviceActivity(id string) (*Resource, error)

GetOrgDeviceActivity fetches a device-management activity (assign/unassign job) by id.

func (*Client) GetPackage added in v0.4.15

func (c *Client) GetPackage(id string) (*Resource, error)

GetPackage fetches a single package (custom app/pkg) by id.

func (*Client) GetUser added in v0.4.15

func (c *Client) GetUser(id string) (*Resource, error)

GetUser fetches a single user by id (users are API-read-only).

func (*Client) GetUserGroup added in v0.4.15

func (c *Client) GetUserGroup(id string) (*Resource, error)

GetUserGroup fetches a single user group by id (read-only).

func (*Client) ListApps

func (c *Client) ListApps() ([]Resource, error)

ListApps returns the organization's apps (Apps & Books; read-only).

func (*Client) ListBlueprints

func (c *Client) ListBlueprints() ([]Resource, error)

ListBlueprints returns all blueprints.

func (*Client) ListConfigurations

func (c *Client) ListConfigurations() ([]Resource, error)

ListConfigurations returns all configurations (every type; only CUSTOM_SETTING is writable).

func (*Client) ListDevices

func (c *Client) ListDevices() ([]Resource, error)

ListDevices returns the organization's devices (orgDevices).

func (*Client) ListMDMDevices added in v0.4.15

func (c *Client) ListMDMDevices() ([]Resource, error)

ListMDMDevices returns the devices enrolled in built-in MDM (mdmDevices).

func (*Client) ListMDMServers

func (c *Client) ListMDMServers() ([]Resource, error)

ListMDMServers returns the organization's MDM servers (read-only).

func (*Client) ListPackages

func (c *Client) ListPackages() ([]Resource, error)

ListPackages returns the organization's packages (custom apps/pkgs; read-only). The endpoint is gated by the built-in-device-management permission, so it may 403 for an account without it.

func (*Client) ListUserGroups

func (c *Client) ListUserGroups() ([]Resource, error)

ListUserGroups returns the organization's user groups (read-only).

func (*Client) ListUsers

func (c *Client) ListUsers() ([]Resource, error)

ListUsers returns the organization's users (read-only; identity is not API-writable).

func (*Client) MDMServerDeviceIDs added in v0.4.15

func (c *Client) MDMServerDeviceIDs(id string) ([]string, error)

MDMServerDeviceIDs returns the orgDevice ids assigned to an MDM server (paginated linkage list).

func (*Client) Raw

func (c *Client) Raw(method, path string, body io.Reader) (int, []byte, error)

Raw issues an authenticated request. For replayable (nil-body) requests it re-mints once on 401 and backs off on 429/5xx (respecting Retry-After).

func (*Client) RemoveBlueprintMembers

func (c *Client) RemoveBlueprintMembers(bpID, rel, memberType string, ids []string) error

RemoveBlueprintMembers detaches members (per-member DELETE) from a blueprint relation.

func (*Client) ResolveApp added in v0.2.0

func (c *Client) ResolveApp(nameOrID string) (*Resource, error)

ResolveApp finds an owned app by id, bundleId, or name. id/bundleId are unique so they win immediately; name may collide, so a name that matches >1 app is an error (caller should use the id/bundleId). App ids are numeric adamIds, not UUIDs, so looksLikeID never matches — always list and match here.

func (*Client) ResolveBlueprint

func (c *Client) ResolveBlueprint(nameOrID string) (*Resource, error)

ResolveBlueprint finds a blueprint by id (UUID) or by its `name` attribute.

func (*Client) ResolveConfig

func (c *Client) ResolveConfig(nameOrID string) (*Resource, error)

ResolveConfig finds a configuration by id (UUID) or by its `name` attribute.

func (*Client) ResolveDevice added in v0.4.15

func (c *Client) ResolveDevice(serialOrID string) (*Resource, error)

ResolveDevice finds an organization device by id or serial number (serials compare case-insensitively). Device ids are serial-shaped, not UUIDs, so looksLikeID never matches — always list and match here.

func (*Client) ResolveMDMServer added in v0.4.15

func (c *Client) ResolveMDMServer(nameOrID string) (*Resource, error)

ResolveMDMServer finds an MDM server by id or by its `serverName` attribute; a name shared by >1 server is an error (caller should use the server id).

func (*Client) ResolvePackage added in v0.4.15

func (c *Client) ResolvePackage(nameOrID string) (*Resource, error)

ResolvePackage finds a package by id or by its `name` attribute; a name shared by >1 package is an error (caller should use the package id).

func (*Client) ResolveUser added in v0.4.15

func (c *Client) ResolveUser(emailOrID string) (*Resource, error)

ResolveUser finds a user by id, email, or managed Apple Account (addresses compare case-insensitively). id is unique so it wins immediately; an address that matches >1 user is an error (caller should use the id).

func (*Client) ResolveUserGroup added in v0.4.15

func (c *Client) ResolveUserGroup(nameOrID string) (*Resource, error)

ResolveUserGroup finds a user group by id or by its `name` attribute; a name shared by >1 group is an error (caller should use the group id).

func (*Client) TokenSource

func (c *Client) TokenSource() *TokenSource

TokenSource exposes the underlying bearer-token source (for whoami/health checks).

func (*Client) UnassignDevices added in v0.4.15

func (c *Client) UnassignDevices(serverID string, deviceIDs []string) (string, error)

UnassignDevices POSTs an UNASSIGN_DEVICES activity removing deviceIDs (orgDevice ids) from the MDM server. It returns the activity id for status polling.

func (*Client) UpdateBlueprint added in v0.4.15

func (c *Client) UpdateBlueprint(id string, name, description *string) error

UpdateBlueprint PATCHes a blueprint's name and/or description. Only fields whose pointer is non-nil are sent; with neither provided it is a no-op (no API call).

func (*Client) UpdateConfiguration

func (c *Client) UpdateConfiguration(id, name, xml string) (updated string, err error)

UpdateConfiguration PATCHes a CUSTOM_SETTING config's name + profile XML and returns the server-assigned updatedDateTime (parsed from the 200 body).

func (*Client) UpdateMDMServer added in v0.4.15

func (c *Client) UpdateMDMServer(id string, name *string, disown *bool) error

UpdateMDMServer PATCHes an MDM server's serverName and/or enableMdmDisownFlag. Only fields whose pointer is non-nil are sent; with neither provided it is a no-op (no API call).

func (*Client) UserGroupUserIDs added in v0.4.15

func (c *Client) UserGroupUserIDs(id string) ([]string, error)

UserGroupUserIDs returns the ids of a user group's members (paginated linkage list).

type LiveBlueprint

type LiveBlueprint struct {
	Name        string
	ID          string
	Description string
	Configs     []string // config names, sorted; an unresolved id passes through as-is
	Apps        []string // app names
	Packages    []string // package names
	Devices     []string // device serial numbers
	Users       []string // user emails (managed Apple Account when email is empty)
	Groups      []string // user-group names
}

LiveBlueprint is a blueprint with the NAMES of its attached members, one list per collection. Configs is always fetched; the other five are fetched only for the collections the caller asked for, so nil means "not fetched" (unknown) — NEVER "empty membership".

func (LiveBlueprint) Members added in v0.4.15

func (l LiveBlueprint) Members(collection string) []string

Members returns the live display-name list for one member collection key.

type LiveConfig

type LiveConfig struct {
	Name    string
	ID      string
	XML     string
	Hash    string
	Updated string
}

LiveConfig is a CUSTOM_SETTING configuration with its raw profile XML.

func (LiveConfig) ContentHash added in v0.4.9

func (l LiveConfig) ContentHash() string

ContentHash returns the known normalized profile hash, deriving it from XML when present.

type Resource

type Resource struct {
	Type       string          `json:"type"`
	ID         string          `json:"id"`
	Attributes json.RawMessage `json:"attributes"`
}

Resource is a JSON:API resource object.

func (Resource) Attr

func (r Resource) Attr() map[string]any

Attr decodes attributes into a generic map (for table output / string fields).

func (Resource) AttrStr

func (r Resource) AttrStr(key string) string

AttrStr returns a string attribute (empty if absent/non-string).

type TokenSource

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

TokenSource mints and caches a bearer token from an ES256 client assertion.

func NewTokenSource

func NewTokenSource(cfg *config.Config, hc *http.Client) *TokenSource

NewTokenSource caches the bearer in a stable, per-credential file (see tokenCachePath).

func (*TokenSource) Expiry

func (ts *TokenSource) Expiry() time.Time

Expiry returns the cached token expiry (after a successful Token()).

func (*TokenSource) Invalidate

func (ts *TokenSource) Invalidate()

Invalidate forces a re-mint on the next Token() (e.g., after a 401).

func (*TokenSource) Token

func (ts *TokenSource) Token() (string, error)

Token returns a valid bearer, minting/refreshing if <60s remain.

Jump to

Keyboard shortcuts

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