From 39f96606d0d9f250b868cf96cb042f8e3ee508bf Mon Sep 17 00:00:00 2001 From: Keaton Svoma Date: Sun, 10 May 2026 19:13:08 -0500 Subject: [PATCH 1/2] docs: add GLOSSARY.md + docs/solutions/ archive MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two artifacts inspired by cli-printing-press, designed to compound over time as institutional memory that future contributors (human and AI) can grep before rediscovering the same patterns. **docs/GLOSSARY.md** — canonical terms for jamf-cli's overlapping vocabulary: Pro vs Platform vs Classic; blueprint vs config profile; smart vs static group; scope vs target; MDM command vs declaration; ADE vs DEP; etc. Closes the "which 'profile' / 'group' / 'policy' do you mean?" ambiguity that costs a round-trip in every AI conversation. **docs/solutions/** — categorized markdown postmortems with YAML frontmatter (title, date, category, module, problem_type, severity, applies_when, tags). Five category subdirs match cli-printing-press: best-practices, conventions, design-patterns, logic-errors, security-issues. Two seed entries: - conventions/output-flag-matrix-2026-05-08.md — exercise -o json/yaml/csv, --quiet, --no-color, --out-file for every new command before declaring done. Captures the lessons from #194 (spinner+NO_COLOR) and #195 (version -v -o json). - design-patterns/cobra-annotations-as-policy-2026-05-11.md — prefer Cobra Annotations for per-command policy metadata (lint:keep-flag, future mcp:hidden, jamf:destructive) over comment magic, separate registries, or per-tool allowlists. Captures the design choice from #198. CLAUDE.md gets a "Read first" section pointing at both so future Claude sessions discover them at session start. Co-Authored-By: Claude Opus 4.7 (1M context) --- CLAUDE.md | 5 + docs/GLOSSARY.md | 100 ++++++++++++++ docs/solutions/README.md | 91 +++++++++++++ .../output-flag-matrix-2026-05-08.md | 100 ++++++++++++++ .../cobra-annotations-as-policy-2026-05-11.md | 127 ++++++++++++++++++ 5 files changed, 423 insertions(+) create mode 100644 docs/GLOSSARY.md create mode 100644 docs/solutions/README.md create mode 100644 docs/solutions/conventions/output-flag-matrix-2026-05-08.md create mode 100644 docs/solutions/design-patterns/cobra-annotations-as-policy-2026-05-11.md diff --git a/CLAUDE.md b/CLAUDE.md index d3d8811c..5618e434 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -2,6 +2,11 @@ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. +## Read first + +- `docs/GLOSSARY.md` — canonical terms for Pro vs Platform vs Classic, blueprint vs config profile, smart vs static groups, scope vs target, etc. Consult before guessing. +- `docs/solutions/` — categorized postmortems and design-pattern docs (e.g., `conventions/output-flag-matrix-2026-05-08.md`, `design-patterns/cobra-annotations-as-policy-2026-05-11.md`). When starting work in a package, grep `docs/solutions/` for matching `module:` or `tags:` frontmatter. + ## CRITICAL: Credential Input Policy **Never accept credentials (passwords, tokens, client secrets) via CLI flags or stdin.** This prevents exposure in shell history, `ps` output, and CI/CD logs. diff --git a/docs/GLOSSARY.md b/docs/GLOSSARY.md new file mode 100644 index 00000000..2744865f --- /dev/null +++ b/docs/GLOSSARY.md @@ -0,0 +1,100 @@ +# Glossary + +Canonical terms used in jamf-cli. When user-facing ambiguity affects what +action to take, ask before acting — the same word often means different +things across Pro, Platform, Protect, and School. + +## Product namespaces + +| Term | Meaning | +|------|---------| +| **Jamf Pro** (`pro`) | The flagship MDM/UEM. Surfaces both the modern **UAPI** (`/api/v1/...`) and the legacy **Classic API** (`/JSSResource/...`). Most commands live here. | +| **Jamf Platform** / **Platform Gateway** (`platform`) | The cross-product API surface hosted at `.apigw.jamf.com`. Adds Blueprints, Compliance Benchmarks, Platform Devices/Groups. Platform auth (`auth-method: platform`) also enables Pro API calls — they're proxied through the gateway at `/api/pro/tenant//...` and `/api/proclassic/tenant//...`. | +| **Jamf Protect** (`protect`) | The EDR/security product. GraphQL only; uses `jamfprotect-go-sdk`. No relation to Pro auth — separate credentials, separate `JAMFPROTECT_*` env vars. | +| **Jamf School** (`school`) | The K-12-focused MDM. Separate REST API; uses `jamfschool-go-sdk`. Separate `JAMFSCHOOL_*` env vars. | + +## API surfaces under Pro + +| Term | Meaning | +|------|---------| +| **UAPI** / **modern API** | The newer Pro JSON REST API at `/api/v1/...` (and `/v2`, `/v3`). What new feature work targets. | +| **Classic API** | The legacy XML API at `/JSSResource/...`. Still widely used; many resources have no UAPI equivalent. Routed through `/api/proclassic/tenant/{id}/...` under Platform gateway auth. | +| **JCDS** | Jamf Cloud Distribution Service — file storage for installer packages. Commands: `pro jcds upload`, `pro jcds download`, `pro jcds sync`. | +| **API integration** / **API client** | An OAuth2 client-credentials pairing registered in Pro (Settings > System > API Roles & Clients). Distinct from a generic API token. | + +## Authentication + +| Term | Meaning | +|------|---------| +| **Token auth** (`auth-method: token`) | Pre-existing bearer token in the `Authorization: Bearer ...` header. Used for legacy basic-auth bootstraps and short-lived UAPI sessions. | +| **OAuth2** (`auth-method: oauth2`) | Client-credentials flow against the instance's `/api/oauth/token`. The standard for modern Pro automation. | +| **Platform** (`auth-method: platform`) | Client-credentials flow against the gateway's `/auth/token`. Requires `--tenant-id`. Enables both Platform API commands AND Pro API commands routed through the gateway. | +| **`keychain:` / `env:` / `file:` references** | Config-file prefixes for resolving secrets at runtime. Bare values are never stored in `config.yaml` — they're moved to keychain on profile creation. | + +## Configuration delivery + +These words look interchangeable but aren't. Picking the wrong one changes +which API you call and which device-side mechanism applies the config. + +| Term | Meaning | +|------|---------| +| **Configuration profile** / **config profile** / **mobileconfig** | An XML `.mobileconfig` payload (legacy Apple format). Delivered via the Pro UAPI or Classic API. Imperative MDM-style. | +| **Declaration** / **DDM** | Declarative Device Management — Apple's newer pull-based config model. Delivered as JSON to the device. | +| **Blueprint** | The Platform API's DDM container. A blueprint bundles multiple **components** (Passcode, Software Update, etc.) into one deployable unit. Lives in Platform, not Pro. | +| **DDM component** | A single declaration inside a blueprint (e.g., `com.apple.passcode`, `software-update-settings`). Each maps to one Apple declaration type. | +| **Legacy-to-DDM conversion** | `import-profile` auto-converts compatible payloads from a mobileconfig into native DDM components. `--legacy` opts out. Unsupported payloads are filtered unless `--include-unsupported` is set. | + +## Groups and scope + +| Term | Meaning | +|------|---------| +| **Smart group** | A dynamic group whose membership is computed from criteria (e.g., "all Macs running macOS 14"). Pro has `smart-computer-groups`, `mobile-device-smart-groups`. Membership refreshes on inventory updates. | +| **Static group** | A manually-curated list of devices. Pro has `static-computer-groups`, `mobile-device-static-groups`. Add/remove by ID. | +| **Scope** | In Pro: which devices/users/groups a policy, profile, or app applies to. The Classic API exposes this as `` XML; UAPI as a `scope` JSON object. | +| **Target** | In Platform: similar concept to Pro's scope, but the API uses "target" (e.g., a blueprint targets device groups). Not interchangeable in code — different field names, different APIs. | +| **Extension Attribute** / **EA** | A custom inventory field defined by a Pro admin (e.g., "Is FileVault enabled?"). Computers and mobile devices have separate EA registries. | + +## MDM mechanics + +| Term | Meaning | +|------|---------| +| **MDM command** | An imperative push to a device (`DeviceLock`, `EraseDevice`, `ClearPasscode`, `UpdateInventory`). Sent via Pro's command API; flushable with `pro computers flush-commands`. | +| **Declaration** (vs MDM command) | Pull-based config. The device fetches its current declaration set on a schedule; no per-command tracking. | +| **Prestage** | Enrollment-prep configuration sent at activation. `computer-prestages` for macOS (ADE/DEP), `mobile-device-prestages` for iOS/iPadOS. | +| **ADE / DEP / Automated Device Enrollment** | Apple's zero-touch enrollment program. "DEP" was the old name; current docs use "ADE" or "Automated Device Enrollment". Both refer to the same flow. | + +## Compliance + +| Term | Meaning | +|------|---------| +| **Compliance benchmark** | A Platform compliance framework (e.g., CIS macOS Benchmark). Has versions; each version contains rules and baselines. | +| **Baseline** | A YAML config within a benchmark version that selects which rules apply. The customer-editable layer. | +| **Rule** | One individual check within a benchmark (e.g., "FileVault must be enabled"). Read-only — vendor-defined. | +| **Compliance report** | The per-device evaluation of a baseline. `pro compliance-benchmarks device-results` returns the latest. | + +## Commands and aliases + +| Term | Meaning | +|------|---------| +| **Generated command** | A command emitted by `make generate` into `internal/commands/{pro,platform}/generated/`. **Never hand-edit these.** Fix the template in `generator/parser/generator.go` instead. | +| **Hand-written command** | A command in `internal/commands/pro_*.go`, `protect_*.go`, `school_*.go`. Owns business logic (upsert, apply, clone, etc.) — wraps generated commands. | +| **`apply`** | Upsert (create-or-update) by name. Hand-written; available on most resources. | +| **`overview`** | A product-level dashboard command. `pro overview` makes ~37 parallel API calls; `protect overview` makes ~14. | +| **Alias** | A short alternate command name, registered in `aliases.go`. E.g., `comp` → `computers`, `bp` → `blueprints`. | + +## Implementation conventions + +| Term | Meaning | +|------|---------| +| **`pro` / `protect` / `school` / `platform`** as command-tree parents | Each product has a bridge file (`pro.go`, `protect.go`, etc.) that wires its subcommands. New commands land under the right bridge. | +| **`cliCtx` / `registry.CLIContext`** | The shared infrastructure handle passed to every command — HTTPClient, AuthProvider, Output formatter, optional PlatformSDKClient/Protect/School clients. | +| **Cobra annotations (`lint:*`, `jamf:*`, `mcp:*`)** | Policy metadata attached to commands. `lint:keep-flag` suppresses the dead-code linter; future namespaces will drive MCP exposure, exit-code policy, destructive-command gating. Read the cobra `Annotations` map, not magic strings in code. | +| **Provenance** | The spec file paths + SHA256 hashes baked into the generated package at `make generate` time. Surfaced via `jamf-cli version -v`. Lets users diagnose "which spec version is this CLI generated from?" without git archaeology. | + +## When to ask + +- **"scope" vs "target"** — if you can't tell from context whether the user means the Pro field or the Platform field, ask. +- **"profile"** — could mean (a) a config-file profile in `~/.config/jamf-cli/`, (b) a mobileconfig configuration profile, (c) a DDM declaration profile. Ask which. +- **"group"** — smart vs static, computer vs mobile — four combinations. Ask if unclear. +- **"policy"** — Pro has policies (`/policies` Classic), Protect has plans (sometimes called "policies"), Platform doesn't have either. Confirm the product. +- **"command"** — could mean a CLI subcommand (`jamf-cli pro computers list`) or an MDM command (a `DeviceLock` push). Context usually disambiguates, but if it doesn't, ask. diff --git a/docs/solutions/README.md b/docs/solutions/README.md new file mode 100644 index 00000000..039412f2 --- /dev/null +++ b/docs/solutions/README.md @@ -0,0 +1,91 @@ +# Solutions + +Documented solutions to past problems — bugs, design patterns, conventions — +that future contributors (human or AI) should learn from rather than rediscover. + +Inspired by [cli-printing-press](https://github.com/mvanhorn/cli-printing-press)'s +`docs/solutions/` archive. The shape is intentionally close to theirs so the +authoring habit transfers cleanly. + +## When to write a solution doc + +Write one when **any** of these apply: + +- You fixed a class of bug, not a single instance. The fix is generalizable, but + the path to discovering it is non-obvious. +- You introduced (or refactored to) a pattern that other parts of the codebase + should adopt. Documenting it now beats explaining it in five future code + reviews. +- A convention was decided that isn't enforceable by lint or tests. The doc + is the enforcement mechanism — reviewers point to it. +- A debugging session took >30 minutes and the next person hitting the same + symptom should be able to short-circuit it. + +Don't write one for: + +- One-off bugs in a single file with no broader lesson. The commit message is + enough. +- Conventions already covered in `CLAUDE.md` or `docs/GLOSSARY.md`. +- Style preferences without a load-bearing reason behind them. + +## Directories + +Group by problem type: + +- `best-practices/` — how to do something well, when more than one way exists +- `conventions/` — rules the codebase follows that aren't enforceable by tooling +- `design-patterns/` — reusable structural patterns with named application sites +- `logic-errors/` — bug classes worth remembering (root cause + correct fix) +- `security-issues/` — anything where the wrong fix has a security cost + +## File format + +Each solution is a single Markdown file. Filename pattern: +`-.md`. The date is the resolution date, not the +discovery date. + +Required YAML frontmatter: + +```yaml +--- +title: "One-line title describing the rule, not the bug" +date: 2026-05-08 +category: conventions # one of the directory names above +module: # e.g., "internal/commands", "generator", "internal/output" +problem_type: convention # design_pattern | convention | bug | best_practice | security +severity: medium # low | medium | high +applies_when: + - "concrete situation 1" + - "concrete situation 2" +tags: [keyword1, keyword2, keyword3] +--- +``` + +Body sections: + +```markdown +## Context + +What happened, what was confusing, what didn't work. Link to PRs, issues, +or commits. + +## Guidance + +The rule itself — actionable, in imperative voice. If there's a code shape, +show the shape. If there's a checklist, list it. + +## Why this beats the alternative (optional) + +Only when "just do X" isn't obvious and the cost of the wrong path is real. +``` + +## Reading these + +Future contributors (human and AI) should `grep` this directory by tag or +keyword when implementing or debugging in a documented area. The frontmatter +is structured so it's easy to search across. + +Future AI sessions: when starting work in a package, scan +`docs/solutions/*/*.md` for matching `module:` or `tags:`. If a solution +covers the area you're touching, follow its guidance rather than rediscovering +the same bug. diff --git a/docs/solutions/conventions/output-flag-matrix-2026-05-08.md b/docs/solutions/conventions/output-flag-matrix-2026-05-08.md new file mode 100644 index 00000000..da1cec0b --- /dev/null +++ b/docs/solutions/conventions/output-flag-matrix-2026-05-08.md @@ -0,0 +1,100 @@ +--- +title: "Every new command must honor the global output/flag matrix" +date: 2026-05-08 +category: conventions +module: internal/commands +problem_type: convention +severity: medium +applies_when: + - "Adding a new top-level command or subcommand" + - "Adding a new code path that writes to stdout or stderr (status messages, hints, spinners)" + - "Adding a verbose mode to an existing command" +tags: + - output + - flags + - no-color + - quiet + - structured-output + - cross-flag-honoring +--- + +# Every new command must honor the global output/flag matrix + +## Context + +Two follow-up fix PRs shipped immediately after the introduction of two new +commands, both because the original work didn't exercise the cross-flag matrix: + +- **PR #194 (spinner+NO_COLOR):** The Pro/Protect/School/Platform spinners + emit `\r` + `\033[K` ANSI to stderr. The wrapping decision consulted + `--quiet` and `-v` but not `--no-color` or the `NO_COLOR` env. Users who set + `NO_COLOR=1` expect ANSI noise to stop, period — that's the + [no-color.org](https://no-color.org) contract. + +- **PR #195 (`version -v` ignoring `-o json/yaml`):** The verbose `version -v` + path hardcoded text output. Passing `-o json` silently still printed text. + Worst of both worlds: the user asked for structured output and got prose. + Fixed by routing the verbose path through the formatter the same way + `doctor` does, with a partitioned `specSources` shape. + +Both fixes are small and obvious in hindsight. The cost was a follow-up PR, +review cycle, and merge for each. + +## Guidance + +For **every** new command or new output path, exercise this matrix before +considering the work complete: + +| Flag / env | Expected behavior | +|------------|-------------------| +| (default) | Human-friendly output | +| `-o json` | Structured JSON; ANSI off; ready to pipe | +| `-o yaml` | Structured YAML | +| `-o csv` | Tabular, where the data is row-shaped | +| `-o table` | Default for lists | +| `--quiet` / `-q` | Suppress advisory output (hints, spinners, progress) | +| `--no-color` or `NO_COLOR=1` | No ANSI escapes anywhere — stdout AND stderr | +| `--out-file ` | Output goes to file; also disable color | +| `--field ` | Single-field extraction | +| `--select ` | Multi-field projection | +| `--compact` | Drop arrays and nested objects | + +### Specific rules + +1. **Anything writing ANSI to stderr** (spinners, status updates, hints) must + consult `noColor` (or `os.Getenv("NO_COLOR") != ""`) alongside `quiet` and + `verboseLevel`. See `shouldShowSpinner()` in `internal/commands/root.go` for + the canonical helper. + +2. **Verbose/structured commands** (commands with a `-v` mode like `doctor` + and `version`) must route their verbose output through `cliCtx.Output.PrintRaw(...)` + when `outputFmt` is `json` or `yaml`, not through hand-written `fmt.Fprintf` + on `os.Stdout`. The formatter knows how to honor the global flags; hand-print + paths don't. + +3. **Marshal structs; don't hand-format prose** when the output is structured. + Define an explicit response struct with JSON tags. Let the formatter handle + indentation, projection, and filtering. + +4. **Test what you ship.** Before merge, run the new command with at least: + ```bash + bin/jamf-cli # default + bin/jamf-cli -o json + bin/jamf-cli -o yaml + bin/jamf-cli --quiet + bin/jamf-cli --no-color + bin/jamf-cli --out-file /tmp/out.txt + ``` + + For commands producing lists, also test `--compact`, `--select`, and + `--field`. + +## Why this beats the alternative + +The alternative is "land the command, fix the flag interactions in follow-up." +That's what happened in #194 and #195. Each follow-up costs a PR, a review, +and a merge — and exposes users to surprising behavior between releases. + +The matrix is short enough to walk every time. A `make smoke-cli` target that +runs each new command through the matrix would automate this; until then, the +checklist above is the discipline. diff --git a/docs/solutions/design-patterns/cobra-annotations-as-policy-2026-05-11.md b/docs/solutions/design-patterns/cobra-annotations-as-policy-2026-05-11.md new file mode 100644 index 00000000..a8e50bed --- /dev/null +++ b/docs/solutions/design-patterns/cobra-annotations-as-policy-2026-05-11.md @@ -0,0 +1,127 @@ +--- +title: "Cobra annotations as policy contract for cross-cutting concerns" +date: 2026-05-11 +category: design-patterns +module: internal/commands +problem_type: design_pattern +severity: low +applies_when: + - "Adding a structural verifier (lint, audit, scorecard) that needs per-command metadata" + - "Designing MCP exposure rules (read-only, destructive, hidden) for commands" + - "Marking commands that intentionally use non-zero exit codes for success-by-policy" + - "Adding a destructive-command confirmation gate that needs an allowlist" +tags: + - cobra + - annotations + - policy + - lint + - mcp + - destructive-commands + - structural-verification +--- + +# Cobra annotations as policy contract for cross-cutting concerns + +## Context + +When jamf-cli's dead-code lint (PR #198) needed an allowlist mechanism for +intentional flag retentions, the choice was between: + +- Comment-based markers (`//lint:keep` above declarations) +- A separate `.linterignore` file with patterns +- Cobra command annotations (`Annotations: map[string]string{"lint:keep-flag": "name1,name2"}`) + +We picked Cobra annotations — and the deciding factor wasn't this single +linter. It was the recognition that every future structural verifier +(anti-reimplementation, MCP-surface-parity, naming-consistency, destructive- +command gating, exit-code policy) will need similar per-command metadata. A +single annotation namespace serves them all. + +The cli-printing-press project ([reference](https://github.com/mvanhorn/cli-printing-press)) +uses the same convention for `pp:endpoint`, `mcp:hidden`, `mcp:read-only`, +`pp:typed-exit-codes`, `pp:novel-static-reference`. Each annotation drives one +or more verifiers without that verifier having to maintain its own allowlist. + +## Guidance + +When you need per-command metadata that a tool (lint, MCP exposure, exit-code +verifier, gate) consumes, **prefer Cobra annotations over string-matching +files, comment magic, or separate registries**. + +### Namespace conventions + +- `lint:*` — for the structural lint suite. Examples: + - `lint:keep-flag: "name1,name2"` — suppress dead-flag finding for these flags + - `lint:keep-func` (future) — suppress dead-func finding for the command's RunE +- `mcp:*` — for the MCP server (when added). Examples: + - `mcp:hidden: "true"` — don't expose this command as an MCP tool + - `mcp:read-only: "true"` — annotate as readOnlyHint when exposed +- `jamf:*` — for jamf-cli policy. Examples: + - `jamf:destructive: "true"` — flag for confirmation gating; also drives MCP destructiveHint + - `jamf:typed-exit-codes: "0,3"` — declares intentional non-zero success codes + +### Reading annotations + +Annotations are `map[string]string` on `*cobra.Command`. Values are bare strings; +encode lists as comma-separated. Readers must handle missing keys (zero value = +no policy applied): + +```go +keep, ok := cmd.Annotations["lint:keep-flag"] +if !ok { + return nil // no opt-outs declared +} +allowed := strings.Split(keep, ",") +``` + +### Writing annotations + +Declare them inline at command construction so the policy is visible next to +the command definition, not in a registry elsewhere: + +```go +cmd := &cobra.Command{ + Use: "delete", + Short: "Delete a computer by ID", + Annotations: map[string]string{ + "jamf:destructive": "true", + "jamf:typed-exit-codes": "0,4", // 4 = not found, treated as success + }, + RunE: func(cmd *cobra.Command, args []string) error { ... }, +} +``` + +### When the static-analysis tool can't read the annotation + +AST readers must handle the case where `Annotations` is set dynamically +(loops, conditionals, function returns). The dead-code lint walks +`*ast.CompositeLit` for the literal `Annotations: map[string]string{...}` +form. If the annotation is set via `cmd.Annotations[...] = ...` after +construction, or returned from a helper, the linter falls back to no +allowlist for that command. + +Prefer the inline literal form so the policy is statically visible. + +## Why this beats the alternative + +**Vs. `//lint:keep` comments:** Comments are positional and brittle — a +refactor that moves a flag binding away from its comment silently disables +the keep. Annotations bind to the command, which is the right granularity. + +**Vs. `.linterignore` file:** A central file becomes write-only history. No +reviewer remembers to check it. The annotation lives next to the command it +governs, so reviewers see it in the diff. + +**Vs. per-tool allowlists in each verifier:** Three verifiers with three +allowlists is three places to forget to update when a command moves. One +annotation namespace, all verifiers read it. + +**Vs. magic strings:** A verifier that string-matches `// HACK keep this` is +indistinguishable from "this comment text accidentally matched." Annotations +are structured data with a defined schema. + +## Related + +- `scripts/lint-dead-code/scan.go` — first consumer of the `lint:*` namespace +- Future structural verifiers should add their own namespace under `lint:*`, + `mcp:*`, or `jamf:*` rather than introducing a new mechanism From a80ea32b6dcf33d6c4086efbb5ea02a4baad46b8 Mon Sep 17 00:00:00 2001 From: Keaton Svoma Date: Sun, 10 May 2026 19:23:35 -0500 Subject: [PATCH 2/2] docs(glossary): correct product-terminology entries against learn.jamf.com MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Validated the glossary against Jamf Product Documentation via Ask Jamf MCP. Several entries had errors from working off codebase signals + training-era knowledge rather than authoritative docs: - **Scope (biggest correction):** Scope in Jamf Pro is the *unified* concept comprising three sub-functions: targets, limitations, exclusions. Targets are *part of* scope, not a separate Platform-only concept. Limitations and exclusions weren't in the glossary at all — added, along with the rule "exclusions always override targets and limitations." - **Blueprint:** Originally described as "the Platform API's DDM container." Actually a Jamf Pro AND Jamf School feature, built on DDM, scoped to smart/static groups. Available in both products. Now also supports configuration-profile payloads alongside declarations. - **DDM:** Was framed as "Apple's newer pull-based config model." Per Apple/Jamf docs, DDM is an *additive* layer on top of MDM, not a replacement. Devices apply declarations proactively and report state via the *status channel*. Added the status channel as its own entry. - **PreStage enrollment:** Capitalization fix (capital S). Added the "settings sync with Apple every two minutes" detail. - **ADE / DEP:** Per Jamf School docs, "DEP" is *explicitly* the formerly- used name. Tightened wording. Added Account-driven Device Enrollment as the macOS 14+ alternative to PreStage. - **Compliance Benchmarks:** Built on the macOS Security Compliance Project (mSCP) framework — added context. The UI uses "benchmark templates" + "rules" + "ODVs"; "baseline" is the Platform-API/CLI term and creates a naming gap. Now documented as such instead of presented as a single layer. - **Extension Attributes:** Added the auto-generated-per-benchmark pattern (`[Benchmark Name] - Failed Result List`). Added a Sources section pointing at the learn.jamf.com docs consulted and calling out that this is a point-in-time capture that should be updated as product renames happen (DEP → ADE, Azure ID → Microsoft Entra ID, etc.). Co-Authored-By: Claude Opus 4.7 (1M context) --- docs/GLOSSARY.md | 62 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/docs/GLOSSARY.md b/docs/GLOSSARY.md index 2744865f..c3c5c312 100644 --- a/docs/GLOSSARY.md +++ b/docs/GLOSSARY.md @@ -38,11 +38,13 @@ which API you call and which device-side mechanism applies the config. | Term | Meaning | |------|---------| -| **Configuration profile** / **config profile** / **mobileconfig** | An XML `.mobileconfig` payload (legacy Apple format). Delivered via the Pro UAPI or Classic API. Imperative MDM-style. | -| **Declaration** / **DDM** | Declarative Device Management — Apple's newer pull-based config model. Delivered as JSON to the device. | -| **Blueprint** | The Platform API's DDM container. A blueprint bundles multiple **components** (Passcode, Software Update, etc.) into one deployable unit. Lives in Platform, not Pro. | -| **DDM component** | A single declaration inside a blueprint (e.g., `com.apple.passcode`, `software-update-settings`). Each maps to one Apple declaration type. | -| **Legacy-to-DDM conversion** | `import-profile` auto-converts compatible payloads from a mobileconfig into native DDM components. `--legacy` opts out. Unsupported payloads are filtered unless `--include-unsupported` is set. | +| **Configuration profile** / **config profile** / **mobileconfig** | An XML `.mobileconfig` payload (legacy Apple format). Delivered via the Pro UAPI or Classic API. Traditional imperative MDM. | +| **Declarative Device Management** / **DDM** | Per Apple, an **additive** layer on top of the MDM protocol. Devices proactively and autonomously apply management settings and report state changes asynchronously via the **status channel**. Not a replacement for MDM — coexists with it on the same enrollment. | +| **Declaration** | A single DDM payload (e.g., `com.apple.configuration.passcode.settings`, `com.apple.configuration.softwareupdate.settings`). The device pulls and applies declarations on its own schedule rather than waiting for an MDM push. | +| **Status channel** | The DDM-specific communication channel devices use to proactively report state changes back to Jamf Pro/School. Some inventory attributes subscribe to this channel and update without an explicit inventory command. | +| **Blueprint** | A **Jamf Pro** AND **Jamf School** feature that bundles DDM declarations (and increasingly, configuration-profile payloads too) into a single deployable unit. Built on DDM. Scoped to smart groups or static groups. Available in both products via the Platform Gateway API surface — *the API lives in `specs/platform/`, but the user-facing concept is a Pro/School feature, not a separate "Platform product".* | +| **Blueprint component** | A single declaration or supported configuration-profile payload inside a blueprint. Newer Apple payloads (AirPrint, Restrictions, Lock Screen Message, etc.) can be added as components alongside DDM declarations. | +| **Legacy-to-DDM conversion** | `import-profile` auto-converts compatible mobileconfig payloads into native DDM components in a blueprint. `--legacy` opts out. Unsupported payloads are filtered unless `--include-unsupported` is set. | ## Groups and scope @@ -50,27 +52,32 @@ which API you call and which device-side mechanism applies the config. |------|---------| | **Smart group** | A dynamic group whose membership is computed from criteria (e.g., "all Macs running macOS 14"). Pro has `smart-computer-groups`, `mobile-device-smart-groups`. Membership refreshes on inventory updates. | | **Static group** | A manually-curated list of devices. Pro has `static-computer-groups`, `mobile-device-static-groups`. Add/remove by ID. | -| **Scope** | In Pro: which devices/users/groups a policy, profile, or app applies to. The Classic API exposes this as `` XML; UAPI as a `scope` JSON object. | -| **Target** | In Platform: similar concept to Pro's scope, but the API uses "target" (e.g., a blueprint targets device groups). Not interchangeable in code — different field names, different APIs. | -| **Extension Attribute** / **EA** | A custom inventory field defined by a Pro admin (e.g., "Is FileVault enabled?"). Computers and mobile devices have separate EA registries. | +| **Scope** | In Jamf Pro, **scope is the unified concept** for "which computers/mobile devices/users receive a remote management task." It comprises three sub-functions: **targets**, **limitations**, and **exclusions** (see below). Classic API exposes scope as `` XML; UAPI as a `scope` JSON object. Scope can be based on individual devices/users, groups, departments, buildings, directory groups, network segments, classes, or iBeacon regions — the available items vary per task type. **Scope cannot be based on personally owned devices.** | +| **Target** (scope sub-function) | The initial pool of intended recipients for a management task. **Required** to deploy any task. *Not* a separate Platform-only concept — targets are part of Pro scope. | +| **Limitation** (scope sub-function) | Optional filter that reduces the target pool to a specific subsection. Requires an initial target. | +| **Exclusion** (scope sub-function) | Optional filter that omits devices/users from the target pool. **Exclusions always override targets and limitations.** | +| **Extension Attribute** / **EA** | A custom inventory field defined by a Pro admin (e.g., "Is FileVault enabled?"). Computers and mobile devices have separate EA registries. Compliance Benchmarks auto-generate per-benchmark EAs (`[Benchmark Name] - Failed Result List`). | ## MDM mechanics | Term | Meaning | |------|---------| -| **MDM command** | An imperative push to a device (`DeviceLock`, `EraseDevice`, `ClearPasscode`, `UpdateInventory`). Sent via Pro's command API; flushable with `pro computers flush-commands`. | -| **Declaration** (vs MDM command) | Pull-based config. The device fetches its current declaration set on a schedule; no per-command tracking. | -| **Prestage** | Enrollment-prep configuration sent at activation. `computer-prestages` for macOS (ADE/DEP), `mobile-device-prestages` for iOS/iPadOS. | -| **ADE / DEP / Automated Device Enrollment** | Apple's zero-touch enrollment program. "DEP" was the old name; current docs use "ADE" or "Automated Device Enrollment". Both refer to the same flow. | +| **MDM command** | An imperative push to a device (e.g., "Send blank push", "Update inventory", "Wipe computer", "Enable/Disable Bluetooth", "OS update — download & install"). Pro tracks pass/fail state per command; flush stuck or failed ones with `pro computers flush-commands`. | +| **DDM** (vs MDM command) | Additive layer — devices pull declarations and report state autonomously via the status channel. Same enrollment runs both; pick the right tool: imperative one-shot action → MDM command; continuously-enforced configuration state → declaration. | +| **PreStage enrollment** | (Capital S — that's the Apple/Jamf canonical spelling.) Configuration applied to devices going through Automated Device Enrollment, configured *before* the device activates. `computer-prestages` for macOS, `mobile-device-prestages` for iOS/iPadOS. Settings sync with Apple every two minutes. | +| **Automated Device Enrollment** / **ADE** | Apple's zero-touch enrollment program. **Formerly DEP.** Jamf docs use "Automated Device Enrollment" or "ADE"; DEP is explicitly the old name. Devices purchased through Apple Business Manager / Apple School Manager auto-enroll without user action. | +| **Account-driven Device Enrollment** | (macOS 14+) Alternative to PreStage where users sign in with a Managed Apple Account in System Settings to initiate enrollment. No URL link required. | ## Compliance | Term | Meaning | |------|---------| -| **Compliance benchmark** | A Platform compliance framework (e.g., CIS macOS Benchmark). Has versions; each version contains rules and baselines. | -| **Baseline** | A YAML config within a benchmark version that selects which rules apply. The customer-editable layer. | -| **Rule** | One individual check within a benchmark (e.g., "FileVault must be enabled"). Read-only — vendor-defined. | -| **Compliance report** | The per-device evaluation of a baseline. `pro compliance-benchmarks device-results` returns the latest. | +| **Compliance Benchmarks** | A **Jamf Pro** feature built on the **macOS Security Compliance Project (mSCP)** framework. Supports industry standards (CIS macOS Benchmarks, etc.) for aligning Mac fleet security posture with recognized practices. | +| **Benchmark** | A specific compliance configuration created from a template (e.g., CIS Level 1). Each benchmark has its own name and gets a Jamf-Pro-auto-generated smart group `[Name] - Compliant` + extension attribute `[Name] - Failed Result List`. | +| **Benchmark template** | The mSCP-derived starting point used when creating a benchmark — e.g., CIS L1, CIS L2, BIO2 (Government Information Security Baseline 2), NLMAPGOV. | +| **Rule** | One individual check within a benchmark (e.g., "FileVault must be enabled"). Vendor-defined; updates flow from mSCP. Some rules accept **ODVs** (Organization-Defined Values) for customization. | +| **Enforcement type** | Per-benchmark setting controlling whether failures auto-remediate. Jamf recommends starting with **Monitor only** to observe before enforcing. | +| **Baseline** *(Platform API term)* | The CLI subcommand and SDK term for the customer-editable YAML config that selects rules within a benchmark version. The Jamf Pro UI doesn't use "baseline" — it talks about "rules" and "ODVs" directly. This is a naming-gap between the underlying Platform API (`compliance-benchmarks baselines`) and the user-facing UI. | ## Commands and aliases @@ -93,8 +100,23 @@ which API you call and which device-side mechanism applies the config. ## When to ask -- **"scope" vs "target"** — if you can't tell from context whether the user means the Pro field or the Platform field, ask. -- **"profile"** — could mean (a) a config-file profile in `~/.config/jamf-cli/`, (b) a mobileconfig configuration profile, (c) a DDM declaration profile. Ask which. +- **"scope"** — could mean (a) the full Pro scope object (targets + limitations + exclusions), (b) just the "targets" sub-function casually called "scope", or (c) Platform's scope field on a blueprint. Different field names in code. +- **"target"** — almost always means a Pro scope sub-function. Don't assume it's a separate Platform concept. +- **"profile"** — could mean (a) a config-file profile in `~/.config/jamf-cli/`, (b) a mobileconfig configuration profile, (c) a Jamf-managed enrollment profile (MDM profile installed at enrollment), (d) a PreStage enrollment payload. Ask which. - **"group"** — smart vs static, computer vs mobile — four combinations. Ask if unclear. -- **"policy"** — Pro has policies (`/policies` Classic), Protect has plans (sometimes called "policies"), Platform doesn't have either. Confirm the product. -- **"command"** — could mean a CLI subcommand (`jamf-cli pro computers list`) or an MDM command (a `DeviceLock` push). Context usually disambiguates, but if it doesn't, ask. +- **"policy"** — Pro has policies (`/policies` Classic), Protect has plans (sometimes informally called "policies"), Platform doesn't have either. Confirm the product. +- **"command"** — could mean a CLI subcommand (`jamf-cli pro computers list`) or an MDM command (a `DeviceLock` push). Context usually disambiguates, but if not, ask. +- **"benchmark" vs "baseline"** — in the Jamf Pro UI, the unit is a *benchmark*, with *rules* and *ODVs*. In the CLI/Platform API, *baseline* shows up as a subcommand because that's the API resource name. They refer to overlapping but not identical things — ask whether the user means the UI concept or the API resource. + +## Sources + +The product-terminology entries above were cross-checked against Jamf Product +Documentation (`learn.jamf.com`) via Ask Jamf — particularly the Jamf Pro +Documentation, Jamf Pro Blueprints Configuration Guide, Compliance Benchmarks +Configuration Guide, and Jamf 100 Course Lesson 17 (Device Scope). When +documentation and CLI behavior diverge (e.g., the `baseline` naming gap), +both are noted. + +If you find an entry that contradicts current `learn.jamf.com` content, fix +the entry — these are point-in-time captures of vocabulary that can drift +with product renames (DEP → ADE, Azure ID → Microsoft Entra ID, etc.).