Skip to content

[AIGTWY-4678] MDM/JAMF bootstrap script for headless ug provisioning - #697

Open
david-siqi-liu wants to merge 3 commits into
mainfrom
david/mdm-bootstrap
Open

david-siqi-liu wants to merge 3 commits into
mainfrom
david/mdm-bootstrap

Conversation

@david-siqi-liu

@david-siqi-liu david-siqi-liu commented Sep 16, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds a headless MDM / JAMF bootstrap for Unity Gateway (AIGTWY-4678):

  • scripts/mdm-bootstrap.sh provisions a bare machine end to end: ensures uv + node, installs ug, writes a PAT-based Databricks profile, runs ug configure --use-pat non-interactively, then probes every workspace-enabled_agents entry 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

  • Provisioning (this script, run as root by JAMF): installs ug + local settings + auth. Runs configure and the probes with stdin from /dev/null so ug stays non-interactive: it writes only local settings and does not attempt the sudo OS-managed reconciliation, so there is no password prompt.
  • Enforcement (scripts/mdm/): JAMF configuration profiles deploy the OS-managed settings that enforce gateway routing even for bare claude / codex launches — Claude Code via com.anthropic.claudecode, Codex via com.openai.codex (base64 TOML). See scripts/mdm/README.md.

How to run it

Inputs are environment variables only (JAMF reserves positional parameters $1-$4).

Required:

  • UG_WORKSPACE_HOST — Databricks workspace URL
  • UG_PAT — personal access token for that workspace

Optional:

  • UG_PROFILE_NAME (default ug-mdm)
  • UG_AGENTS (default: the workspace's enabled_agents)
  • UG_INSTALL_SPEC (default git+https://github.com/databricks/unity-gateway)
  • UG_NODE_VERSION (only used if node is absent)
  • UG_SKIP_PROBE (set to skip the inference probe)

Invocation used to test (macOS):

UG_WORKSPACE_HOST="https://eng-ml-agent-platform.staging.cloud.databricks.com" \
UG_PAT="<pat>" \
./mdm-bootstrap.sh

For JAMF: deploy the script unchanged and upload a 3-line wrapper as the policy script that maps JAMF parameters $5/$6 to UG_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)

  • ug headless auth is PAT-only; no service-principal (OAuth M2M) path for fleet machine identity.
  • ug can't emit the OS-managed profile payloads for MDM packaging (only writes them in place via interactive sudo).

Test evidence (macOS, arm64)

==> Unity Gateway MDM bootstrap (Darwin/arm64)

==> Validating inputs
  ✓ workspace: https://eng-ml-agent-platform.staging.cloud.databricks.com
  ✓ profile:   ug-mdm
    agents: from workspace enabled_agents

==> Dependency: curl + git
  ✓ curl and git present

==> Dependency: uv
  ✓ uv present (uv 0.12.3 (507230998 2026-08-07 aarch64-apple-darwin))

==> Dependency: node + npm
  ✓ node present (v24.20.0), npm present (11.19.0)

==> Installing Unity Gateway (ug)
    uv tool install --force git+https://github.com/databricks/unity-gateway
Resolved 52 packages in 6.10s
Installed 52 packages in 30ms
 + unity-gateway==0.1.0+176.gceb7730 (from git+https://github.com/databricks/unity-gateway@ceb7730fd0c87dbb0db731fc5821f34bfd3e65ed)
   (+ 51 dependency packages)
Installed 2 executables: ucode, ug
  ✓ ug installed (0.1.0+176.gceb7730)

==> Writing Databricks CLI profile [ug-mdm]
  ✓ wrote profile to /Users/david.l/.databrickscfg (mode 600)

==> Configuring ug (headless, PAT)
    ug configure --profile ug-mdm --use-pat
✔ Databricks auth already available for https://eng-ml-agent-platform.staging.cloud.databricks.com
✔ Unity Gateway connected
✔ A managed config is published for your workspace.
• Applying it to the agents your admin enabled: Claude Code, Codex.
• Updated Claude Code: ~/.claude/ucode-settings.json, /Library/Application Support/ClaudeCode/managed-settings.json
• Updated Codex: ~/.codex/ucode.config.toml, ~/.ucode/codex-model-catalog.json, /etc/codex/managed_config.toml
╭────────────────────── Workspace-managed config ───────────────────────╮
│ Workspace: https://eng-ml-agent-platform.staging.cloud.databricks.com │
│ Enabled agents: Claude Code, Codex                                    │
│ MCPs: none configured                                                 │
│ Skills: none configured                                               │
╰───────────────────────────────────────────────────────────────────────╯
• You're all set — run `ug` to launch with your managed settings.
  ✓ ug configured

==> Probing enabled agents (real inference)
  ✓ claude responded: ✔ Databricks auth already available for  https://eng-ml-agen
  ✓ codex responded: ✔ Databricks auth already available for  https://eng-ml-agen
    probed 2 agent(s), 0 failed
  ✓ all enabled agents responded

==> Done
  ✓ ug is installed and configured; enabled agents verified.
    Run 'ug' to launch the default agent.

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 configure this 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.

@david-siqi-liu david-siqi-liu added the quicktree-assisted PR created with quicktree-assisted workflow label Sep 16, 2026
@david-siqi-liu
david-siqi-liu marked this pull request as ready for review September 16, 2026 23:39
david-siqi-liu and others added 2 commits September 17, 2026 16:59
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>
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>
Comment thread scripts/mdm-bootstrap.sh

configure_ug() {
section "Configuring ug (headless, PAT)"
local args=(configure --profile "$UG_PROFILE_NAME" --use-pat)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

quicktree-assisted PR created with quicktree-assisted workflow

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants