commands

package
v1.29.0 Latest Latest
Warning

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

Go to latest
Published: Sep 11, 2026 License: MIT Imports: 80 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var BackupResources = []BackupResource{

	{Key: "classic-policies", FilterName: "policies", SubDir: "policies"},

	{Key: "classic-macos-config-profiles", FilterName: "profiles", SubDir: "profiles/macos"},
	{Key: "classic-mobile-config-profiles", FilterName: "profiles", SubDir: "profiles/ios"},

	{Key: "computer-prestages", FilterName: "prestages", SubDir: "prestages/computers", ScopePath: "/v2/computer-prestages/{id}/scope"},
	{Key: "mobile-device-prestages", FilterName: "prestages", SubDir: "prestages/mobile", ScopePath: "/v2/mobile-device-prestages/{id}/scope"},

	{Key: "scripts", FilterName: "scripts", SubDir: "scripts"},

	{Key: "computer-extension-attributes", FilterName: "extension-attributes", SubDir: "extension-attributes/computer"},
	{Key: "mobile-device-extension-attributes", FilterName: "extension-attributes", SubDir: "extension-attributes/mobile"},
	{Key: "classic-user-ext-attrs", FilterName: "extension-attributes", SubDir: "extension-attributes/user"},

	{Key: "computer-groups-smart-groups", FilterName: "smart-groups", SubDir: "smart-groups/computers"},
	{Key: "computer-groups-static-groups", FilterName: "static-groups", SubDir: "static-groups/computers"},

	{Key: "mobile-device-groups-smart-groups", FilterName: "smart-groups", SubDir: "smart-groups/mobile"},
	{Key: "mobile-device-groups-static-groups", FilterName: "static-groups", SubDir: "static-groups/mobile"},

	{Key: "classic-advanced-computer-searches", FilterName: "advanced-searches", SubDir: "advanced-searches/computers", DropKeys: []string{"computers"}},
	{Key: "advanced-mobile-device-searches", FilterName: "advanced-searches", SubDir: "advanced-searches/mobile"},

	{Key: "categories", FilterName: "categories", SubDir: "categories"},
	{Key: "buildings", FilterName: "buildings", SubDir: "buildings"},
	{Key: "departments", FilterName: "departments", SubDir: "departments"},

	{Key: "sites", FilterName: "sites", SubDir: "sites", ListOnly: true},

	{Key: "classic-mac-apps", FilterName: "mac-apps", SubDir: "mac-apps"},
	{Key: "classic-mobile-apps", FilterName: "mobile-apps", SubDir: "mobile-apps"},

	{Key: "classic-packages", FilterName: "packages", SubDir: "packages"},
	{Key: "classic-printers", FilterName: "printers", SubDir: "printers"},
	{Key: "classic-dock-items", FilterName: "dock-items", SubDir: "dock-items"},

	{Key: "classic-network-segments", FilterName: "network-segments", SubDir: "network-segments"},
	{Key: "classic-restricted-software", FilterName: "restricted-software", SubDir: "restricted-software"},
	{Key: "classic-disk-encryption-configs", FilterName: "disk-encryption", SubDir: "disk-encryption"},

	{Key: "patch-software-title-configurations", FilterName: "patch-titles", SubDir: "patch-titles"},

	{Key: "classic-account-users", FilterName: "accounts", SubDir: "accounts/users"},
	{Key: "classic-account-groups", FilterName: "accounts", SubDir: "accounts/groups"},
}

BackupResources is the curated set of resources included in `backup` and `diff`. Endpoint paths live in generated/backup_registry.go; this file only decides which resources are in scope and how they lay out on disk.

Grouping follows a logical config-object order: policies/profiles first, then scripts/EAs/groups, then supporting objects, then administration.

Functions

func AnnotateScopeLevelError added in v1.29.0

func AnnotateScopeLevelError(cmd *cobra.Command, err error) error

AnnotateScopeLevelError appends the levels a platform command declares to a gateway scope error, when the credential in hand is not at one of them.

It replaces annotateAuditScopeError, which spelled the same fact for one command by hand and had already gone stale once. Reading x-scope-types means the sentence cannot disagree with the artifact, and every platform command gets it rather than the one whose gap someone hit.

It says "declares" rather than "requires" on purpose. The spec is currently STRICTER than the gateway: build v2082 moved six Platform specs to environment-only, and a tenant credential still reaches platform-devices and platform-device-groups today (probed 2026-09-05). So this annotates a failure the gateway has already returned and never pre-empts one — a refusal keyed on this data would refuse working commands.

Silent when the credential's level is among the declared ones: the scope is then not the story, and a note about scope would send the reader away from whatever is.

func BackupFilterNames added in v1.11.0

func BackupFilterNames() []string

BackupFilterNames returns the unique set of FilterName values (sorted) — used for CLI help text and completion hints.

func BackupSubDirs added in v1.28.0

func BackupSubDirs() map[string]string

BackupSubDirs maps each curated resource's on-disk subdirectory (relative to the backup root, slash-separated) to the FilterName that owns it. `diff` reads this table rather than walking the backup tree, so files off disk are bucketed under exactly the key live mode uses and a directory and an instance are comparable; it also uses the key set to tell which directories in the backup root a curated resource already owns from those it must key by name.

It matters because many of the curated resources nest two levels deep (profiles/macos, smart-groups/computers, accounts/users, advanced-searches/computers, …). `diff` used to treat every top-level directory as a resource and read only the files sitting directly inside it, so every nested resource contributed nothing to either snapshot and its changes were reported as no change at all — silently, exit 0.

Deliberately no tally: this comment said thirteen while the table held fifteen, and a number nothing reads is wrong again the first time the table grows. Read the table.

func BoundedParallelFetch

func BoundedParallelFetch[T any, R any](ctx context.Context, items []T, concurrency int, fn func(context.Context, T) (R, error)) ([]R, []error)

BoundedParallelFetch runs fn for each item with bounded concurrency. Returns all results (in input order) and any errors collected.

func ClassifyError added in v1.19.0

func ClassifyError(err error) error

ClassifyError normalizes framework errors that carry no explicit exit code so they map to the documented codes. Cobra's flag-group and required-flag validators report a wrong invocation as a plain error, which defaults to exit 1; classify those as a usage error (2) to match the unknown-flag path handled by SetFlagErrorFunc. Errors that already carry an exit code pass through unchanged — including the unknown-flag errors and every argument-count error, which classifyArgsErrors codes at its own call site.

Only two prefixes were listed at first, so `pro backup` with no --output exited 1 while `pro backup --nosuchflag` exited 2, the two halves of one mistake answering differently on every command in the CLI that calls MarkFlagRequired. Exit 1 is this CLI's generic failure, so a wrapper could not tell "you invoked it wrong" from "the request failed", which is the whole distinction exitcode.Usage exists to draw.

func DeduplicateSlug

func DeduplicateSlug(slug string, seen map[string]bool) string

DeduplicateSlug appends a numeric suffix if slug already exists in the set. Returns the unique slug and adds it to the set.

func EnrichPrivilegeError added in v1.22.0

func EnrichPrivilegeError(cmd *cobra.Command, err error) error

EnrichPrivilegeError names the permission a 403 wanted, in the vocabulary of whichever API served the command.

The two vocabularies are independent sets and neither is derivable from the other. A Jamf Pro instance enforces API-role privileges ("Read Categories"), granted in Jamf Pro. The Jamf Platform gateway enforces GA capability permissions (categories:read), granted in Jamf Account when the API integration is created; the GA consolidation folded several Jamf Pro privileges into one capability, and Jamf Account no longer offers the old names at all. So printing the wrong one sends the operator to a console where the grant it names does not exist.

Three cases, in the order they are checked:

  • A Platform command (jamf:api platform-gateway, which covers the gateway-served Security Cloud commands too). Its jamf:privileges annotation is already the capability vocabulary, and its error comes from the platform SDK rather than internal/client, so nothing has mapped it to an exit code yet.
  • A Pro or Classic command whose 403 hint already carries a platform answer: internal/client wrote it, for the request it actually sent, on a gateway credential. Left alone — appending the Jamf Pro names here is the bug this whole function exists to avoid.
  • Everything else: a Pro or Classic 403 against a Jamf Pro instance, where the annotation's Jamf Pro privilege names are the right answer.

func FetchAllPaginated

func FetchAllPaginated(ctx context.Context, client registry.HTTPClient, basePath string, pageSize int) ([]map[string]any, error)

FetchAllPaginated fetches all items from a modern API endpoint. It auto-detects the response format:

  • Paginated: `{"totalCount": N, "results": [...]}` — fetches all pages
  • Array: `[{...}, {...}]` — returns the full array directly

Some Jamf Pro endpoints (e.g. /v1/sites, /v1/computer-groups, /v2/patch-software-title-configurations) return plain arrays even when pagination params are provided. This function handles both transparently.

func FetchClassicList

func FetchClassicList(ctx context.Context, client registry.HTTPClient, path, wrapperKey string) ([]any, error)

FetchClassicList performs a GET on a Classic API list endpoint and returns the unwrapped array. Classic API returns XML; JSON is handled as a fallback.

func FetchClassicListSubset added in v1.11.0

func FetchClassicListSubset(ctx context.Context, client registry.HTTPClient, path, subset string) ([]map[string]any, error)

FetchClassicListSubset performs a GET on a Classic API endpoint that hosts multiple sibling collections under a single root (currently only /JSSResource/accounts, which nests <users> and <groups> inside <accounts>) and returns the items belonging to the named subset. The runtime mirror of the list_subset manifest opt-in handled by the classic generator in PR 152.

func FetchJSON

func FetchJSON(ctx context.Context, client registry.HTTPClient, path string) (map[string]any, error)

FetchJSON performs a GET request and returns the parsed JSON object. Exported version of the overview.go fetchJSON helper.

func FormatError

func FormatError(err error) bool

FormatError writes a structured JSON error to stdout when the output format is "json". Returns true if the error was handled, false otherwise (caller should fall back to plain stderr).

func FprintError added in v1.19.0

func FprintError(w io.Writer, err error)

FprintError writes a human-facing error (and a "hint:" line when present) to w. Used by main when the JSON envelope path does not apply.

func NewRootCmd

func NewRootCmd(version, commit, date, specProVersion string) *cobra.Command

func ResolveAuthForProfile

func ResolveAuthForProfile(cfg *config.Config, params AuthParams) (string, auth.Provider, error)

ResolveAuthForProfile determines the server URL and auth provider for a specific profile name using the given config. Unlike resolveAuth, it reads none of the package-level flag variables — every input arrives in params — which is what makes it callable per profile (e.g. in the diff command).

It does write two package vars, and the contract is that both are per resolution rather than cumulative: withheldProfileScope, reset at the top here so a stale record cannot put a sentence about the wrong profile on a later error, and resolvedPlatformScope, reset for the same reason and then written by newPlatformSDKClient when a client is built. Sequential calls are therefore safe and each answers for the profile it was given; two concurrent ones are not, and `pro diff` resolves its two sides in sequence.

func SlugifyName

func SlugifyName(name string) string

SlugifyName converts a display name to a filesystem-safe slug. "Deploy Chrome - v1.2" → "deploy-chrome-v1-2"

func StripServerFields

func StripServerFields(obj map[string]any) map[string]any

StripServerFields removes server-generated fields from a JSON object for clean diffing. Removes id, timestamps, and other server-set fields.

Types

type AuthParams

type AuthParams struct {
	Profile      string
	ServerURL    string
	Token        string
	TokenFile    string
	TokenStdin   bool
	ClientID     string
	ClientSecret string
	// TenantID and EnvironmentID are the two scope identifiers a platform
	// integration can name, and they are mutually exclusive — see the scope
	// handling in ResolveAuthForProfile. Neither set means organization scope.
	TenantID      string
	EnvironmentID string
}

AuthParams holds all auth-related inputs for profile resolution. Enables callers (like diff) to resolve multiple profiles independently.

type BackupResource added in v1.11.0

type BackupResource struct {
	Key        string // lookup in generated.BackupEndpoints
	FilterName string // --resources filter token
	SubDir     string // output subdirectory under --output
	// ListOnly bypasses the per-ID detail fetch — each list item is written
	// directly to disk as its own file. Used for resources whose list response
	// is already the complete record (e.g. sites: {id, name}).
	ListOnly bool
	// ScopePath, when set, names a per-ID device-scope endpoint
	// (e.g. "/v2/computer-prestages/{id}/scope"). After fetching each detail
	// record the backup/diff code fetches this path and embeds the sorted
	// serial numbers under a "scope" key so the assignment list travels with
	// the prestage config in a single, diff-friendly file.
	ScopePath string
	// DropKeys names top-level response keys that are executed output rather
	// than configuration, removed by dropResponseKeys in both backup and diff.
	//
	// A Classic advanced-search GET runs the search and returns the devices it
	// currently matches. That membership is not configuration: it churns on
	// every inventory change, it is never equal between two instances, and it
	// carries device names and UDIDs into a directory meant for version
	// control. StripServerFields cannot do this job — it drops ids and
	// timestamps generically, and it is skipped under --include-ids, which is
	// about identifiers rather than about membership.
	DropKeys []string
}

BackupResource is a curated entry in the backup/diff resource set. Each entry names a generated CLI command (Key) whose list+get endpoints are resolved at runtime from generated.BackupEndpoints. FilterName is the user-facing token accepted by --resources (e.g. "profiles" covers both macOS and iOS profiles); SubDir is the output directory under the backup root.

Rule of thumb: prefer a modern-API resource over its classic counterpart when both exist (modern responses are richer and paginated). Only fall back to classic when there is no modern equivalent.

type FetchResult

type FetchResult[R any] struct {
	Value R
	Err   error
}

FetchResult holds either a result or an error from a parallel fetch.

type ResolvedBackupResource added in v1.11.0

type ResolvedBackupResource struct {
	BackupResource
	generated.BackupEndpoint
}

ResolvedBackupResource couples a curated entry with its generated endpoint metadata. Runtime code iterates the resolved form so it doesn't need to cross-reference two slices at every step.

func ResolveBackupResources added in v1.11.0

func ResolveBackupResources(filter []string) ([]ResolvedBackupResource, error)

ResolveBackupResources joins the curated BackupResources against the generated endpoint registry, optionally filtering by user-supplied resource names (matched against FilterName). An unknown filter name produces an empty result; a filter name that matches zero curated entries is reported by the caller.

An entry whose Key is missing from generated.BackupEndpoints is a programming error — a regenerated registry and a stale curation list have diverged — and surfaces via an error so tests catch the drift at build time.

Source Files

Directories

Path Synopsis
platform
pro
security

Jump to

Keyboard shortcuts

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