Documentation
¶
Overview ¶
Package mdm reads MDM-managed configuration from platform-native sources (plist on macOS, registry on Windows, UserDefaults on iOS, RestrictionsManager on Android). The returned Policy is consumed by profilemanager.Config.apply() as the highest-priority override layer.
An empty Policy (no source present, or source present with zero keys) means no MDM enforcement is active and the client behaves as if the feature did not exist.
Index ¶
- Constants
- Variables
- func CanonicalURL(s string) string
- func ResolveConflicts(policy *Policy, checks []ConflictCheck) []string
- type ChangeDetector
- type ConflictCheck
- type Features
- type Fields
- type Loader
- type Policy
- func (p *Policy) GetBool(key string) (bool, bool)
- func (p *Policy) GetInt(key string) (int64, bool)
- func (p *Policy) GetString(key string) (string, bool)
- func (p *Policy) GetStringSlice(key string) ([]string, bool)
- func (p *Policy) HasKey(key string) bool
- func (p *Policy) IsEmpty() bool
- func (p *Policy) ManagedKeys() []string
- type PolicyFetcher
- type Restrictions
- type Ticker
Constants ¶
const ( KeyManagementURL = "managementURL" KeyDisableUpdateSettings = "disableUpdateSettings" KeyDisableProfiles = "disableProfiles" KeyDisableNetworks = "disableNetworks" // KeyDisableAdvancedView gates the advanced-view section in the // upcoming UI revision. UI-only: NOT stored on Config, not // applied by applyMDMPolicy, not rejectable via SetConfig. The // daemon surfaces it through GetFeatures (tristate: present // true / present false / absent) and the same key appears in // GetConfigResponse.mDMManagedFields when set. KeyDisableAdvancedView = "disableAdvancedView" KeyDisableClientRoutes = "disableClientRoutes" KeyDisableServerRoutes = "disableServerRoutes" KeyBlockInbound = "blockInbound" KeyDisableMetricsCollection = "disableMetricsCollection" KeyAllowServerSSH = "allowServerSSH" KeyDisableAutoConnect = "disableAutoConnect" // KeyDisableAutostart suppresses the GUI's fresh-install // launch-on-login default and marks the Settings toggle as // MDM-managed. UI-only: NOT stored on Config and not applied by // applyMDMPolicy; the GUI reads it directly and it appears in // GetConfigResponse.mDMManagedFields when set. KeyDisableAutostart = "disableAutostart" KeyRosenpassEnabled = "rosenpassEnabled" KeyRosenpassPermissive = "rosenpassPermissive" KeyWireguardPort = "wireguardPort" KeyEnableLocalMetrics = "enableLocalMetrics" KeyLocalMetricsAddress = "localMetricsAddress" // Split tunnel is modeled as a single conceptual policy with two // registry/plist values. KeySplitTunnelMode is the discriminator // ("allow" or "disallow"); KeySplitTunnelApps is a comma-separated // list of package names. The values are mutually exclusive by // construction — only one mode can be set at a time. KeySplitTunnelMode = "splitTunnelMode" KeySplitTunnelApps = "splitTunnelApps" // KeyLazyConnection forces the lazy-connection feature on or off, overriding // the management feature flag. Read as a bool (native bool, or on/off, // true/false, 1/0, yes/no); absent = defer to management. KeyLazyConnection = "lazyConnection" // KeyRemoteJobsAllowed opts the peer into management-requested remote jobs // (e.g. debug bundles). Read as a bool; absent = defer to the local config // (which defaults to disabled). Stored on Config as RemoteJobsAllowed. KeyRemoteJobsAllowed = "allowRemoteJobs" // KeyBundleUploadURL overrides the debug-bundle upload service URL for // remote jobs, taking precedence over the management-supplied value. Read // as a string; must be an https URL with a host. Absent = defer to the // management-supplied URL (or the default upload server). KeyBundleUploadURL = "debugBundleUploadURL" )
Well-known policy keys. Names mirror the corresponding ConfigInput Go field names (lowerCamelCase) so the daemon can map a Policy key directly to a configuration field.
const ( SplitTunnelModeAllow = "allow" SplitTunnelModeDisallow = "disallow" )
Split-tunnel mode literals (KeySplitTunnelMode values).
const DefaultReloadInterval = 1 * time.Minute
DefaultReloadInterval is the production cadence at which the desktop daemon re-reads the OS-native MDM policy. Picked to balance responsiveness against registry/plist I/O overhead. Mobile builds use OS-side notifications instead, hence anticipating the ticker mechanism entirely.
PreSharedKeyRedactedSentinel is the redaction mask returned in place of a real pre-shared key; an incoming value equal to it is a round-trip echo, never an override.
Variables ¶
var SecretKeys = map[string]struct{}{ KeyPreSharedKey: {}, KeyBundleUploadURL: {}, }
SecretKeys lists keys whose values must be redacted in logs.
Functions ¶
func CanonicalURL ¶ added in v0.79.0
CanonicalURL normalizes a service URL by appending the scheme default port when none is present; unparseable input is returned unchanged.
func ResolveConflicts ¶ added in v0.79.0
func ResolveConflicts(policy *Policy, checks []ConflictCheck) []string
ResolveConflicts returns the names of keys whose requested value diverges from the policy-enforced value; keys the policy does not manage are skipped, a managed key without a Check counts as a conflict.
Types ¶
type ChangeDetector ¶ added in v0.79.0
type ChangeDetector struct {
// contains filtered or unexported fields
}
ChangeDetector tracks the last observed policy of a Loader so an OS-notification-driven caller can ask whether the managed configuration actually changed before restarting anything.
func NewChangeDetector ¶ added in v0.79.0
func NewChangeDetector(loader *Loader) *ChangeDetector
NewChangeDetector constructs a ChangeDetector seeded with the loader's current policy, so only a later change reports as changed.
func (*ChangeDetector) Changed ¶ added in v0.79.0
func (d *ChangeDetector) Changed() bool
Changed re-reads the policy, logs the per-key diff, and reports whether it diverged from the last observation; the new snapshot becomes the baseline.
type ConflictCheck ¶ added in v0.79.0
ConflictCheck is a value-aware comparison between a single requested field and the corresponding MDM-enforced value.
func ConflictBool ¶ added in v0.79.0
func ConflictBool(key string, p *bool) ConflictCheck
ConflictBool builds a ConflictCheck for a boolean MDM key.
func ConflictInt64 ¶ added in v0.79.0
func ConflictInt64(key string, p *int64) ConflictCheck
ConflictInt64 builds a ConflictCheck for an integer MDM key.
func ConflictStringPtr ¶ added in v0.79.0
func ConflictStringPtr(key string, p *string) ConflictCheck
ConflictStringPtr builds a ConflictCheck for an optional string MDM key, where an explicit empty value is still a request to change the setting. A nil p means "field not set" (no override requested).
func ConflictURL ¶ added in v0.79.0
func ConflictURL(key, got string) ConflictCheck
ConflictURL builds a ConflictCheck for a URL-typed MDM key. The two sides are compared as the endpoints they address, not as strings: see util.SameServiceURL.
type Features ¶ added in v0.79.0
type Features struct {
DisableProfiles bool `json:"disableProfiles"`
DisableNetworks bool `json:"disableNetworks"`
DisableUpdateSettings bool `json:"disableUpdateSettings"`
}
Features carries the feature gates a UI must honor.
type Fields ¶ added in v0.79.0
type Fields struct {
ManagementURL string `json:"managementURL"`
WireguardPort bool `json:"wireguardPort"`
RosenpassEnabled bool `json:"rosenpassEnabled"`
RosenpassPermissive bool `json:"rosenpassPermissive"`
DisableClientRoutes bool `json:"disableClientRoutes"`
DisableServerRoutes bool `json:"disableServerRoutes"`
AllowServerSSH *bool `json:"allowServerSSH"`
DisableAutoConnect bool `json:"disableAutoConnect"`
DisableAutostart bool `json:"disableAutostart"`
BlockInbound bool `json:"blockInbound"`
DisableMetricsCollection bool `json:"disableMetricsCollection"`
SplitTunnelMode bool `json:"splitTunnelMode"`
SplitTunnelApps bool `json:"splitTunnelApps"`
RemoteJobsAllowed bool `json:"allowRemoteJobs"`
DisableAdvancedView *bool `json:"disableAdvancedView"`
}
Fields carries the per-key MDM enforcement state for a UI: value-typed fields hold the enforced value (nil pointer = not managed), boolean fields report that the key is managed.
type Loader ¶ added in v0.79.0
type Loader struct {
// contains filtered or unexported fields
}
Loader is the DI-friendly entry point for reading the active MDM policy. Construct one at the daemon's lifecycle owner (Server on desktop, gomobile-exposed bridge on mobile) and pass it to anything that needs to read MDM state (the reload ticker, profilemanager's Config). Each callsite has the Loader handed in instead of looking up package-level state.
func NewJSONLoader ¶ added in v0.79.0
NewJSONLoader constructs a Loader whose policy source is a JSON-encoded object string, as produced by the mobile native layers; a nil fetch disables MDM enforcement.
func NewLoader ¶ added in v0.79.0
func NewLoader(f PolicyFetcher) *Loader
NewLoader constructs a Loader. A non-nil fetcher takes precedence over the platform-native source; production desktop callers pass nil so the registry / plist stays authoritative.
func (*Loader) Load ¶ added in v0.79.0
Load reads the platform-native MDM configuration and returns a Policy. Returns an empty (but non-nil) Policy when no source is present, the source is empty, or the platform is unsupported.
Diagnostic logging differentiates the three states:
- source absent / unsupported platform: trace log only
- source present, zero keys: info "MDM enrolled (no managed keys)"
- source present, N keys: info "MDM enrolled with N managed keys: [...]"
type Policy ¶
type Policy struct {
// contains filtered or unexported fields
}
Policy holds MDM-managed settings read from the platform source. A nil or empty Policy means no enforcement is active.
func NewPolicy ¶
NewPolicy constructs a Policy from a key→value map. Pass nil or an empty map to construct an empty (no-enforcement) Policy. The returned *Policy is always non-nil.
func (*Policy) GetBool ¶
GetBool returns the managed value for key coerced to bool, and whether the key was set. Accepts native bool and string literals (true/false, 1/0, yes/no, on/off), case-insensitively and trimmed of surrounding whitespace.
func (*Policy) GetInt ¶
GetInt returns the managed value for key as int64, and whether the key was set. Accepts native int / int64 (as produced by the Windows registry loader for REG_DWORD/REG_QWORD) and numeric strings (decimal).
func (*Policy) GetString ¶
GetString returns the managed value for key coerced to string, and whether the key was set. A non-string value returns ("", false).
func (*Policy) GetStringSlice ¶
GetStringSlice returns the managed value for key as []string, and whether the key was set. Accepts []string, []any (of strings), and a single string (treated as a one-element list).
func (*Policy) ManagedKeys ¶
ManagedKeys returns the sorted list of managed key names. Returns an empty slice (not nil) on an empty Policy.
type PolicyFetcher ¶ added in v0.79.0
PolicyFetcher supplies the managed configuration to a Loader. Mobile platforms (Android / iOS) implement it to push the OS-managed values into the Go runtime. On every platform a non-nil fetcher takes precedence over the native source, which is the test seam for the registry / plist loaders; a nil fetcher leaves the native source in charge, or disables MDM enforcement where there is none.
type Restrictions ¶ added in v0.79.0
Restrictions is the UI-facing enforcement snapshot; the JSON shape is shared by the desktop frontend and the mobile bridges.
func BuildRestrictions ¶ added in v0.79.0
func BuildRestrictions(policy *Policy) Restrictions
BuildRestrictions derives the UI enforcement snapshot from the active policy.
func (Restrictions) JSON ¶ added in v0.79.0
func (r Restrictions) JSON() (string, error)
JSON renders the snapshot in the shared UI JSON shape.
type Ticker ¶
type Ticker struct {
// contains filtered or unexported fields
}
Ticker periodically re-reads the OS-native MDM policy via the injected Loader and invokes the onChange callback (supplied to Run) whenever the observed Policy diverges from the last observation (added / removed / changed keys). Launch with Run from a goroutine; cancel the supplied context to stop.
func NewTicker ¶
NewTicker constructs a Ticker that will re-read the OS-native policy every reloadInterval once Run is called. The Loader is injected so the ticker doesn't depend on any package-level state — production passes the daemon-owned Loader, tests pass a fake Loader (built with a fake PolicyFetcher).
The initial snapshot is populated by calling loader.Load() at construction time so the first tick only fires onChange when the policy actually changed since boot — without this baseline the first tick would report every currently-managed key as "added" and trigger a spurious engine restart.