> ## Documentation Index
> Fetch the complete documentation index at: https://silmaril.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Jamf Pro

> Deploy Silmaril with a device profile and a scoped package policy.

export const macosRelease = {
  "version": "0.3.22",
  "build": "1077",
  "guardianEnabled": false,
  "minimumOS": "macOS 14 or later",
  "dmgUrl": "https://downloads.silmaril.dev/macos/releases/0.3.22/1077/Silmaril-0.3.22-1077-guardian-disabled.dmg",
  "pkgUrl": "https://downloads.silmaril.dev/macos/releases/0.3.22/1077/Silmaril-0.3.22-1077-guardian-disabled.pkg",
  "mdmZipUrl": "https://downloads.silmaril.dev/macos/releases/0.3.22/1077/Silmaril-0.3.22-1077-guardian-disabled-MDM.zip",
  "mdmChecksumUrl": "https://downloads.silmaril.dev/macos/releases/0.3.22/1077/Silmaril-0.3.22-1077-guardian-disabled-MDM.zip.sha256",
  "mdmSHA256": "86efaf60414339c97c5fcaac86d98b215f44010798f58e83ea3850b1243fd92a"
};

<a id="jamf" />

Deploy Stable {macosRelease.version} (build {macosRelease.build}) with a Computer Level profile and a scoped package policy.

## Deploy with Jamf Pro

<Steps>
  <Step title="Prepare">
    Have administrator access, an enrolled Mac running {macosRelease.minimumOS}, and the vendor management agent where required. Download the Stable {macosRelease.version} ({macosRelease.build}) Guardian Disabled PKG and complete the required configuration before upload.

    **Expected result**<br />
    The completed `Silmaril-Managed.mobileconfig` has passed validation, and the package is the <a href={macosRelease.pkgUrl}>Stable PKG</a>.

    **If this differs**<br />
    Finish the [rollout plan](/docs/macos/managed-deployment) before creating the Jamf profile or package policy.
  </Step>

  <Step title="Upload the device profile">
    In Computers > Configuration Profiles, upload the completed `Silmaril-Managed.mobileconfig` as a Computer Level profile set to Install Automatically. Scope it to a dedicated Silmaril rollout group, either smart or static. Leave unrelated profiles on their existing scopes. Signed profiles are read-only in Jamf. An unsigned import may change content, so export and compare the stored payload. When `dev.silmaril.mdm.managed` already exists, use Jamf's supported replacement workflow and never randomize UUIDs. If the console cannot replace a signed profile, pause only the Silmaril app install policy, plan removal and reimport with the same supplied identity, verify restored policy on pilot Macs, then resume that app installation.

    **Expected result**<br />
    The stored payload matches the completed file, including every supplied identifier, UUID, and permission payload.

    **If this differs**<br />
    Export the stored profile and compare it with the file you uploaded. Restore the supplied identity before enabling the package policy. Inventing new UUIDs is outside this workflow.
  </Step>

  <Step title="Confirm profile installation">
    Use the target computer record's Management and History views to confirm the profile install command completed and the profile is installed before enabling the package policy. For a later cohort, keep that package policy disabled until the new Macs show the profile installed. Adding computers to a group whose package policy is already enabled does not recreate this order.

    **Expected result**<br />
    The profile install command completed and the profile is installed on the pilot Mac.

    **If this differs**<br />
    Leave the package policy disabled until that record shows the profile installed. A scoped profile that has not finished installing is not a reason to deploy the PKG.
  </Step>

  <Step title="Upload and deploy the PKG">
    Upload the {macosRelease.version} ({macosRelease.build}) PKG in Settings > Computer management > Packages. Create a build-specific policy with Recurring check-in, Once per computer, package action Install, no restart, and the same Silmaril rollout group as the profile. Run the verify-and-launch script after the package. It checks bundle ID `dev.silmaril.SilmarilMacOS`, build {macosRelease.build}, and Guardian Disabled, then opens Silmaril for the console user or relies on login launch when nobody is signed in.

    **Expected result**<br />
    The policy installs that Guardian Disabled PKG once, does not restart the Mac, and the script exits 0. Exit 0 with a console user above UID 500 also opens Silmaril. Exit 0 with no signed-in user leaves launch to the next login.

    **If this differs**<br />
    The script's failure message names the mismatch. It can report a missing app, an unreadable bundle ID or build, an unexpected bundle ID, a build older than {macosRelease.build}, or a Guardian variant that does not match this policy. Correct that result before treating the policy as successful. Package success alone does not mean protection is active.
  </Step>

  <Step title="Verify">
    Open Silmaril on a pilot Mac and complete [endpoint verification](/docs/macos/verify). The profile supplies the connection values. Package success or a Managed label alone does not confirm protection.

    **Expected result**<br />
    Endpoint verification shows the app identity, a Managed connection, and fresh Protection activity from a new agent session.

    **If this differs**<br />
    Keep the rollout on the pilot. Use [troubleshooting](/docs/macos/troubleshooting). Restart required means fully quit and reopen the affected agent, then start a new session.
  </Step>

  <Step title="Update or replace policy">
    For an update, deploy only the intended Guardian Disabled version and update supported app/package metadata at the same time. Replace the existing profile while preserving all supplied profile and payload identifiers, UUIDs, and permissions. Never invent identifiers to bypass a conflict. Removing managed keys restores saved local preferences. Removing the profile does not uninstall Silmaril.

    For every new app version, create a new version-specific Once per computer policy and script with the new minimum build. Disable old installer policies before enabling the new one. Editing an old Once per computer policy does not rerun it on Macs that already completed it.

    **Expected result**<br />
    Pilot Macs that already completed an older policy receive the new build only from the new policy, and Settings shows the intended Guardian Disabled build.

    **If this differs**<br />
    A Mac left on an older completed policy still has the previous install. Create and enable the new policy after the old installer policy is disabled, then [verify](/docs/macos/verify) again.
  </Step>

  <Step title="Uninstall">
    Disable every Silmaril package policy for the target Macs so Jamf cannot reinstall the app. Leave unrelated policies and groups in place.

    Removing a computer from the rollout group is not an uninstall procedure. Keep baseline profile and policy scopes unchanged. Do not delete a group that also scopes other controls.

    Run the shared [Uninstall through MDM](/docs/macos/uninstall) script as root with the affected user signed in, and retain the JSON receipt and exit code. Exit 2 reports remaining items to review. It does not identify Guardian residue.

    Follow the shared result-handling instructions and remove only the Silmaril profile when policy should no longer apply. Leave baseline assignments and controls in place.

    Upload the script in Settings > Computer management > Scripts and add it to a scoped script-only policy under Computers > Policies. Set Once per computer and leave restart disabled.

    **If this differs**<br />
    Use that exit-code table before retrying. A missing app or helper does not prove that earlier cleanup completed.
  </Step>
</Steps>

## Verify-and-launch script

`MIN_BUILD` is the numeric Stable build {macosRelease.build}. `EXPECTED_GUARDIAN` is `false` for this Guardian Disabled policy. The script opens Silmaril only after the bundle ID, build, and Guardian variant match.

```bash theme={"theme":"github-light-default"}
#!/bin/bash

APP="/Applications/Silmaril.app"
PLIST="$APP/Contents/Info.plist"
EXPECTED_BUNDLE_ID="dev.silmaril.SilmarilMacOS"
MIN_BUILD="1077"
EXPECTED_GUARDIAN="false"

fail() { echo "$1" >&2; exit 1; }
[[ -x "$APP/Contents/MacOS/Silmaril" && -f "$PLIST" ]] || fail "Silmaril is not installed."
bundle_id="$(/usr/libexec/PlistBuddy -c "Print :CFBundleIdentifier" "$PLIST" 2>/dev/null)" || fail "Cannot read bundle ID."
build="$(/usr/libexec/PlistBuddy -c "Print :CFBundleVersion" "$PLIST" 2>/dev/null)" || fail "Cannot read build."
guardian="$(/usr/libexec/PlistBuddy -c "Print :SilmarilPrivilegedProtectionEnabled" "$PLIST" 2>/dev/null)" || fail "Cannot read Guardian variant."
[[ "$bundle_id" == "$EXPECTED_BUNDLE_ID" ]] || fail "Unexpected bundle ID: $bundle_id"
case "$build" in ''|*[!0-9]*) fail "Invalid build: $build" ;; esac
(( 10#$build >= 10#$MIN_BUILD )) || fail "Installed build $build is older than $MIN_BUILD."
[[ "$guardian" == "$EXPECTED_GUARDIAN" ]] || fail "Installed Guardian variant does not match this policy."

console_uid="$(/usr/bin/stat -f %u /dev/console)" || fail "Cannot read console user."
case "$console_uid" in ''|*[!0-9]*) fail "Invalid console user." ;; esac
[[ "$console_uid" -gt 500 ]] || exit 0
/bin/launchctl asuser "$console_uid" /usr/bin/sudo -n -H -u "#$console_uid" /usr/bin/open "$APP"
```

## Vendor references

* [Upload a macOS configuration profile](https://learn.jamf.com/r/en-US/jamf-pro-documentation-current/Uploading_a_Configuration_Profile_macOS)
* [Smart groups](https://learn.jamf.com/r/en-US/jamf-pro-documentation-current/Smart_Groups)
* [Package management](https://learn.jamf.com/r/en-US/jamf-pro-documentation-current/Package_Management)
* [Scripts](https://learn.jamf.com/r/en-US/jamf-pro-documentation-current/Scripts)
* [Policy management](https://learn.jamf.com/r/en-US/jamf-pro-documentation-current/Policy_Management)
