Documentation
¶
Index ¶
- Constants
- func AttachSchemas(resources []ClassicResource, art *classicschema.Artifact) error
- type ClassicFileField
- type ClassicResource
- func (r ClassicResource) CredentialFields() []string
- func (r ClassicResource) EnumChoices() []EnumChoice
- func (r *ClassicResource) ExtraLookups() []string
- func (r ClassicResource) HasBodySchema() bool
- func (r *ClassicResource) HasLookup(lookup string) bool
- func (r *ClassicResource) HasOperation(op string) bool
- func (r ClassicResource) RepeatedElementKeys() []string
- func (r ClassicResource) RepeatedElements() map[string]string
- func (r ClassicResource) RequiredFields() []string
- func (r ClassicResource) ScaffoldXML() (string, error)
- func (r ClassicResource) SetCompletions() []string
- func (r ClassicResource) SetFieldTypeKeys() []string
- func (r ClassicResource) SetFieldTypes() map[string]string
- func (r ClassicResource) TopLevelOptionalFields() []string
- type EnumChoice
- type GatewayVerdict
- type Generator
Constants ¶
const CodegenHeader = "// Code generated by jamf-cli generator (classic). DO NOT EDIT."
CodegenHeader is the marker line at the top of every classic API generated file. Must match the first line of classicResourceTemplate and classicRegistryTemplate.
Variables ¶
This section is empty.
Functions ¶
func AttachSchemas ¶ added in v1.28.0
func AttachSchemas(resources []ClassicResource, art *classicschema.Artifact) error
AttachSchemas binds each Classic resource to the request-body schema the committed artifact names for it, so the template can emit --scaffold, --set and required/enum help.
A nil artifact attaches nothing and is not an error: Classic commands then ship exactly as they did before the artifact existed, reading their body from --from-file or stdin with no guidance. `make generate` has to work in a tree where nobody has fetched an SDK spec.
The schemas are loaded through kin-openapi so $ref resolves — a Classic schema refers to a dozen shared components (site, category, id_name, scope) — and then through parser.SchemaFromOpenAPI, so a Classic body is walked by the same code that walks a Pro, Platform or Security Cloud one.
Types ¶
type ClassicFileField ¶ added in v1.11.0
type ClassicFileField struct {
Flag string // CLI flag name, e.g. "mobileconfig-file"
XMLPath string // Slash-delimited path under the resource root, e.g. "general/payloads"
Encoding string // "xml-cdata" | "raw"
Desc string // Flag description shown in --help
NameFallback string // "none" | "keep-ext" | "strip-ext"
PreservePayloadIdentifiers bool // If true, fetch existing payloads on update and call profileconvert.InjectIdentifiers
FetchMergePut bool // If true, apply must fetch existing record, overlay only the file field, and PUT
}
ClassicFileField declares a resource field whose value is sourced from a local file via a dedicated CLI flag on create/update/apply. The file contents are injected as children of a named XML parent before the body is sent. Encoding controls how the file contents are embedded: "xml-cdata" wraps them in a CDATA section (for mobileconfig), "raw" inserts the XML subtree as-is (for AppConfig plists).
type ClassicResource ¶
type ClassicResource struct {
Name string // e.g., "policies"
Path string // URL segment under /JSSResource/: "policies"
CLIName string // e.g., "classic-policies"
GoName string // e.g., "ClassicPolicies"
Singular string // JSON root key for a single object: "policy"
Description string
Operations []string // ["list", "get", "create", "update", "delete"]
Lookups []string // ["id", "name", "serialnumber", "macaddress", "udid"]
HasScope bool // true if the resource supports scope operations
IDPath string // path segment between base path and ID value; defaults to "id" (e.g. "groupid" → /accounts/groupid/{id})
IsConfigProfile bool // true for macOS and mobile device configuration profile resources
HasCustomPayload bool // true only for osxconfigurationprofiles (supports --custom-payload-file)
FileFields []ClassicFileField
// ListSubset marks a list operation as sharing the list endpoint with a
// sibling resource: GET /JSSResource/{path} returns both, and the generated
// list command extracts only the named sub-element before formatting.
// Used for /accounts (returns users + groups combined under <accounts>).
// Empty for normal list endpoints.
ListSubset string
// GroupPath is the Classic API path (without /JSSResource/) for the group
// list/detail endpoints, e.g. "mobiledevicegroups". When set, delete gets
// a --group flag that resolves members and deletes them in bulk.
GroupPath string
// Subsets is the curated list of server-side subset section names a get
// command exposes via --subset (e.g. General, Commands for computerhistory).
// Drives shell completion only; values are passed through to the API
// verbatim, so unknown values still work. Empty when the resource declares
// no subsets.
Subsets []string
// GatewayLevel and GatewayDetail record whether the Jamf Platform gateway
// exposes this resource at all, from specs/gateway/coverage.json.
// Resource-level because a Classic resource's paths are built at runtime
// from Path plus the lookup in play, so there is no fixed set of paths to
// enumerate. Empty when the gateway serves it or when no manifest was
// available.
GatewayLevel string
GatewayBasis string
GatewayDetail string
// GatewayMethods narrows that verdict to the HTTP method a subcommand
// sends, keyed by method. A resource can be served and still have a dead
// subcommand: Classic API 11.28.0 withdrew every read on patchsoftwaretitles
// while keeping POST /patchsoftwaretitles/id/{}, so the resource is carried
// and `list`, `get`, `update` and `delete` are all refused. The method is
// fixed at generate time even though the path is not, and a method the
// gateway declares nowhere beneath the resource cannot work under any
// lookup. Absent key or empty Level means served.
GatewayMethods map[string]GatewayVerdict
// GatewayList is the verdict for the collection GET — /JSSResource/{Path}
// with no lookup, the one Classic path that IS fixed at generate time. It is
// separate from GatewayMethods["GET"] because a resource can keep GET on its
// {id} paths and lose it on the collection, which is what 11.28.0 did to
// patchpolicies: `get` works, `list` does not.
GatewayList GatewayVerdict
// GatewayPrivileges are the Jamf Account capability permissions the gateway
// requires, keyed by HTTP method — per method rather than per resource
// because that is the granularity that differs (accounts:read for a GET,
// accounts:update for a PUT), even though the served/unserved verdict above
// is resource-wide. A different vocabulary from Jamf Pro's own privilege
// names, and Classic commands carry none of those.
GatewayPrivileges map[string][]string
// BodySchema is the request-body shape for create/update/apply, parsed from
// the committed specs/classic/schemas.json artifact. Nil when the artifact
// is absent or names no schema for this resource — six of the manifest's
// resources have none, four of them withdrawn from the Classic API
// altogether — in which case the resource ships without --scaffold, --set or
// field help, exactly as every Classic resource did before the artifact
// existed.
//
// The Classic manifest is hand-written and carries no field information, so
// this is the only route by which a Classic write command can say what goes
// in its body.
BodySchema *parser.Schema
// BodyRoot is the XML root element a request body must be wrapped in, e.g.
// "policy". Read off the spec (a schema's xml.name, else its component key)
// rather than reused from Singular, so a disagreement between the two is
// reported at derivation time instead of silently picking one.
BodyRoot string
// BodySchemaName is the component schema key BodySchema was parsed from,
// recorded so generated help can name its provenance.
BodySchemaName string
}
ClassicResource represents a Classic API resource parsed from the YAML manifest.
func ParseManifest ¶
func ParseManifest(path string) ([]ClassicResource, error)
ParseManifest reads the Classic API YAML manifest and returns a sorted slice of ClassicResource structs with all defaults applied.
func (ClassicResource) CredentialFields ¶ added in v1.28.0
func (r ClassicResource) CredentialFields() []string
CredentialFields lists the dotted paths whose value is a credential, so the generated --set refuses them.
The repo's credential policy forbids passwords, tokens and client secrets in flag values, because a flag value lands in shell history, in `ps` output and in CI logs. None of the three existing --set implementations enforces it, and on the Classic surface that gap is wide: an SMTP server, an LDAP server, a distribution point, a GSX connection, a VPP account and a directory binding all carry one, and `apply`/`create`/`update` are exactly the commands a caller reaches for. So Classic refuses the pair and names --from-file instead, rather than inheriting a hazard the policy already rules out.
Matched on the field name — or, where the leaf name alone is too generic to be safe, on the dotted path — and not on a schema marker: the Classic spec declares writeOnly 28 times in total and on none of these fields.
func (ClassicResource) EnumChoices ¶ added in v1.28.0
func (r ClassicResource) EnumChoices() []EnumChoice
EnumChoices lists every enum-constrained field in the resource's body schema, as dotted paths with a "[]" segment marking an array element.
This is the part of the schema the wire will not teach you. Probed on a live tenant 2026-09-02: the Classic API does not enforce its own enums. A policy created with `<frequency>Twice per fortnight</frequency>` answers 201 and reads back `Once per computer`; a computer group criterion with `<and_or>maybe</and_or>` answers 201 and reads back `and`. The value is silently replaced with the default, with no error and no warning — so a caller who guesses wrong gets a working object that does the wrong thing, and --help is the only place the legal set can come from.
func (*ClassicResource) ExtraLookups ¶
func (r *ClassicResource) ExtraLookups() []string
ExtraLookups returns lookups beyond "id" (e.g., name, serialnumber, macaddress, udid).
func (ClassicResource) HasBodySchema ¶ added in v1.28.0
func (r ClassicResource) HasBodySchema() bool
HasBodySchema reports whether a resource carries enough shape for --scaffold and --set to be worth emitting.
func (*ClassicResource) HasLookup ¶
func (r *ClassicResource) HasLookup(lookup string) bool
HasLookup returns true if the resource supports the given lookup type.
func (*ClassicResource) HasOperation ¶
func (r *ClassicResource) HasOperation(op string) bool
HasOperation returns true if the resource supports the given operation.
func (ClassicResource) RepeatedElementKeys ¶ added in v1.28.0
func (r ClassicResource) RepeatedElementKeys() []string
RepeatedElementKeys returns RepeatedElements' keys in sorted order.
func (ClassicResource) RepeatedElements ¶ added in v1.28.0
func (r ClassicResource) RepeatedElements() map[string]string
RepeatedElements maps an array-typed dotted path to the element name its members are wrapped in, so the runtime --set builder can render XML.
Classic models a repeated element as a JSON array whose items carry one named object child: `<criteria><criterion>…</criterion></criteria>` is declared as `criteria: {type: array, items: {properties: {criterion: {...}, size: {...}}}}`. The element name is not derivable from the array's own name — `criteria` holds `criterion`, `computers` holds `computer`, `scope.limit_to_users.user_groups` holds `user_group` — so it is read off the schema and recorded here.
func (ClassicResource) RequiredFields ¶ added in v1.28.0
func (r ClassicResource) RequiredFields() []string
RequiredFields lists the fields the spec marks required on the body's own schema, in sorted order.
Worth surfacing because the server's answer to a missing required field is an HTTP 409 carrying an HTML error page — `Error: ComputerGroup name is required` buried in a `<body style="font-family: sans-serif;">` — one field at a time. It is discoverable, but only by trying.
Top level only, and deliberately not the whole tree. A nested `required` means "required *if* the enclosing object is sent", and every Classic object that declares one sits under an optional parent: computer_group's only nested entry is site.name, so reporting it would tell a caller that a group cannot be created without naming a site, which is false. When a Classic schema first declares a required object, this needs to grow the ancestor check rather than the whole tree.
func (ClassicResource) ScaffoldXML ¶ added in v1.28.0
func (r ClassicResource) ScaffoldXML() (string, error)
ScaffoldXML renders the resource's request-body template as XML.
func (ClassicResource) SetCompletions ¶ added in v1.28.0
func (r ClassicResource) SetCompletions() []string
SetCompletions lists the scalar dotted paths worth offering as shell completions for --set, each with a trailing "=".
Two exclusions, both because a completion is a suggestion and suggesting something that will be refused is worse than suggesting nothing:
- Objects and arrays. --set cannot set either as a whole, and the generated parser refuses them by name with an explanation.
- Credential fields. --set refuses these on purpose, so offering `read_write_password=` at the shell prompt would walk a caller straight into the thing the credential policy exists to prevent — and it is the shell that records the command line.
func (ClassicResource) SetFieldTypeKeys ¶ added in v1.28.0
func (r ClassicResource) SetFieldTypeKeys() []string
SetFieldTypeKeys returns SetFieldTypes' keys in sorted order, so the generated literal is stable across runs.
func (ClassicResource) SetFieldTypes ¶ added in v1.28.0
func (r ClassicResource) SetFieldTypes() map[string]string
SetFieldTypes maps every settable dotted path in the body schema to its spec type, for the generated --set parser to coerce against.
Schema-driven rather than a looks-like-JSON heuristic, following the modern Pro generator: docs/solutions/logic-errors/set-array-object-stringification-2026-07-24.md records what the heuristic costs, and Classic makes it worse. Classic XML is untyped on the wire, so `--set general.name=42` has to stay the string "42" and a boolean field has to render `true` rather than `1`; nothing in the response would reveal a wrong guess.
func (ClassicResource) TopLevelOptionalFields ¶ added in v1.28.0
func (r ClassicResource) TopLevelOptionalFields() []string
TopLevelOptionalFields lists the resource's top-level body sections that are not required, in sorted order.
Top level only, deliberately. A Classic policy has 271 fields at depth 5, and an exhaustive optional list in --help would bury the required one; the full tree is what --scaffold is for.
type EnumChoice ¶ added in v1.28.0
EnumChoice is one constrained field and the values it accepts.
type GatewayVerdict ¶ added in v1.28.0
GatewayVerdict is one gateway-coverage verdict in the three string values the template renders as annotations. Strings rather than generator/gateway's own types so this package needs no dependency on it — generator/main.go converts at the one point the two meet.
type Generator ¶
type Generator struct {
// contains filtered or unexported fields
}
Generator generates Go command files from ClassicResource definitions.
func NewGenerator ¶
NewGenerator creates a new Classic API code generator.
func (*Generator) Generate ¶
func (g *Generator) Generate(resource ClassicResource) (string, error)
Generate writes a Go command file for a single Classic API resource.
func (*Generator) GenerateRegistry ¶
func (g *Generator) GenerateRegistry(resources []ClassicResource) (string, error)
GenerateRegistry writes the classic_registry.go file that registers all Classic commands.