[AIGTWY-4678] MDM/JAMF bootstrap script for headless ug provisioning - #697
david-siqi-liu wants to merge 3 commits into
Conversation
scripts/mdm-bootstrap.sh provisions a bare machine end to end: ensures uv + node, installs ug, writes a PAT Databricks profile, runs `ug configure --use-pat` headlessly (which also installs the enabled agent CLIs), then probes every managed enabled_agents entry with a one-shot inference call. Inputs are env vars only (JAMF-safe). For JAMF mass deployment (AIGTWY-4678). Co-authored-by: Isaac <no-reply@databricks.com>
Run `ug configure` and the agent probes with stdin from /dev/null so ug stays non-interactive: it writes only local settings and never attempts the sudo OS-managed reconciliation, removing the password prompt (matches JAMF's non-TTY behavior). Add scripts/mdm/ with JAMF configuration-profile templates for the OS-managed enforcement layer, deployed separately from provisioning: Claude Code via com.anthropic.claudecode and Codex via com.openai.codex (base64 TOML), plus a README explaining the two-layer split. For AIGTWY-4678. Co-authored-by: Isaac <no-reply@databricks.com>
5763a53 to
182e4e7
Compare
387cc4e to
c4ce28e
Compare
Add `test_ug_configure_managed_via_pat`: configure the managed workspace through a `[ug-mdm]` PAT profile + `ug configure --profile ug-mdm --use-pat`, exactly as scripts/mdm-bootstrap.sh does, and assert the same managed-config outcome (no selector, admin's static models in Claude's picker and Codex's catalog) plus `use_pat` in state and a real launch. This is the only coverage of the MDM headless auth path; existing managed CUJs use `--workspace` plus the runner's bearer. The token comes from the durable `E2E_ADMIN_SP_PAT` CI secret (a stored SP-minted PAT; the runner's own bearer is hourly M2M). Thread that secret through the runner's pytest env allowlist and the managed workflow job; the test skips when it's unset. For AIGTWY-4678. Co-authored-by: Isaac <no-reply@databricks.com>
c4ce28e to
81b3374
Compare
|
|
||
| configure_ug() { | ||
| section "Configuring ug (headless, PAT)" | ||
| local args=(configure --profile "$UG_PROFILE_NAME" --use-pat) |
There was a problem hiding this comment.
This makes the bootstrap PAT the persistent inference credential, not just a credential for downloading workspace configuration. The script writes it to .databrickscfg, then --use-pat persists use_pat=True in ug state. Subsequent launches call apply_pat_environment(), which exports that PAT as DATABRICKS_BEARER; the generated agent auth helpers also retain --use-pat and return that same token for gateway requests.
If JAMF distributes one PAT across the fleet, those clients therefore perform inference as the PAT's owner rather than as the individual developer. Restricting that credential to configuration reads would break the configure/probe/runtime flow because it also needs inference access. File mode 0600 does not remove the shared credential from the endpoint.
We should separate provisioning from runtime authentication: fetch the configuration centrally and distribute a credential-free file through MDM, then use each developer's OAuth identity for inference. The endpoint bootstrap should not persist or select the fleet bootstrap PAT as the agent's ongoing authentication method.
Summary
Adds a headless MDM / JAMF bootstrap for Unity Gateway (AIGTWY-4678):
scripts/mdm-bootstrap.shprovisions a bare machine end to end: ensuresuv+node, installsug, writes a PAT-based Databricks profile, runsug configure --use-patnon-interactively, then probes every workspace-enabled_agentsentry with a real one-shot inference call through the gateway.scripts/mdm/holds JAMF configuration-profile templates for the OS-managed enforcement layer, deployed separately from provisioning.Two-layer model
ug+ local settings + auth. Runsconfigureand the probes with stdin from/dev/nullsougstays non-interactive: it writes only local settings and does not attempt thesudoOS-managed reconciliation, so there is no password prompt.scripts/mdm/): JAMF configuration profiles deploy the OS-managed settings that enforce gateway routing even for bareclaude/codexlaunches — Claude Code viacom.anthropic.claudecode, Codex viacom.openai.codex(base64 TOML). Seescripts/mdm/README.md.How to run it
Inputs are environment variables only (JAMF reserves positional parameters
$1-$4).Required:
UG_WORKSPACE_HOST— Databricks workspace URLUG_PAT— personal access token for that workspaceOptional:
UG_PROFILE_NAME(defaultug-mdm)UG_AGENTS(default: the workspace'senabled_agents)UG_INSTALL_SPEC(defaultgit+https://github.com/databricks/unity-gateway)UG_NODE_VERSION(only used ifnodeis absent)UG_SKIP_PROBE(set to skip the inference probe)Invocation used to test (macOS):
For JAMF: deploy the script unchanged and upload a 3-line wrapper as the policy script that maps JAMF parameters
$5/$6toUG_WORKSPACE_HOST/UG_PAT(snippet in the script header, staying clear of the reserved$1-$4).Known gaps (surfaced by this work, to track separately)
ugheadless auth is PAT-only; no service-principal (OAuth M2M) path for fleet machine identity.ugcan't emit the OS-managed profile payloads for MDM packaging (only writes them in place via interactivesudo).Test evidence (macOS, arm64)
Note: the "Updated ... managed-settings.json / managed_config.toml" lines reflect OS-managed files already present and compatible from an earlier interactive run on this test machine. The non-interactive
configurethis script uses does not create or modify the OS-managed files on a fresh machine (per the managed-settings behavior matrix); those are deployed via the Layer 2 profiles.This pull request and its description were written by Isaac.