<?xml version="1.0" encoding="utf-8"?>
<!--
  Bolt Desktop (native app) - Windows Group Policy administrative template.

  The Windows counterpart of bolt-desktop.mobileconfig. Deploy it and admins get
  real Group Policy Editor UI (Computer Configuration > Administrative Templates
  > Bolt Desktop) instead of hand-authoring registry keys, and Intune can ingest
  the same file for MDM-managed machines. Deployment steps and verification:
  the Windows guide at sparcle.app/trust/managed-deployment/.

  WHERE THIS WRITES, AND WHY IT MATTERS

    HKLM\SOFTWARE\Policies\Sparcle\Bolt     <- every policy below

  That is the tree Bolt treats as the FORCED tier: a value found
  there comes back `forced: true`, wins the merge for switches and
  configuration, and renders in the app as "Managed by your organization". It is
  the only tree the Group Policy Editor can write, and it is ACL'd to
  administrators.

  Two rules follow, and both are enforced by tests in Bolt rather than by
  anyone remembering:

  * Every policy here is machine scope. A user-scoped policy would write the
    per-user hive, which Bolt deliberately never reads (any local user can
    write their own hive with `reg add`, and a forced source wins the merge, so
    reading it would be a privilege escalation). Such a policy would look
    applied in the editor and do nothing at all on the device.
  * The catalogue below matches the list of keys Bolt reads exactly. A registry value
    outside that catalogue is silently ignored by the app, so an extra policy
    here would be inert rather than a bug anyone would see.

  For a value that should be an admin-settable DEFAULT rather than a locked
  policy, a provisioning script writes the sibling tree
  HKLM\SOFTWARE\Sparcle\Bolt instead. Bolt reads it, reports it unforced, and
  the Group Policy Editor never touches it. See the doc.

  LIST-VALUED POLICIES are multi-line text boxes, not the Group Policy "list"
  control. That is deliberate: the list control writes each entry as a separate
  REG_SZ under a numbered subkey, whereas Bolt reads one REG_MULTI_SZ per key.
  Enter one host / bundle id per line.
-->
<policyDefinitions revision="1.0" schemaVersion="1.0"
                   xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions">
  <policyNamespaces>
    <target prefix="boltdesktop" namespace="Sparcle.Policies.BoltDesktop" />
    <using prefix="windows" namespace="Microsoft.Policies.Windows" />
  </policyNamespaces>

  <resources minRequiredRevision="1.0" />

  <supportedOn>
    <definitions>
      <definition name="SUPPORTED_BoltDesktop" displayName="$(string.SUPPORTED_BoltDesktop)" />
    </definitions>
  </supportedOn>

  <categories>
    <category name="BoltDesktop" displayName="$(string.CAT_BoltDesktop)"
              explainText="$(string.CAT_BoltDesktop_Help)" />
  </categories>

  <policies>

    <!-- ============ Enforcement level (Kind::Level) ============
         Most-restrictive wins across every source, even over a forced value -
         so this cannot be used to relax a stricter policy set centrally. -->
    <policy name="DlpMode" class="Machine" displayName="$(string.DlpMode)"
            explainText="$(string.DlpMode_Help)"
            key="SOFTWARE\Policies\Sparcle\Bolt"
            presentation="$(presentation.DlpMode)">
      <parentCategory ref="BoltDesktop" />
      <supportedOn ref="SUPPORTED_BoltDesktop" />
      <elements>
        <enum id="DlpMode_Enum" valueName="dlpMode" required="true">
          <item displayName="$(string.DlpMode_Off)"><value><string>off</string></value></item>
          <item displayName="$(string.DlpMode_Warn)"><value><string>warn</string></value></item>
          <item displayName="$(string.DlpMode_Redact)"><value><string>redact</string></value></item>
          <item displayName="$(string.DlpMode_Block)"><value><string>block</string></value></item>
        </enum>
      </elements>
    </policy>

    <!-- ============ Feature switches (Kind::Switch) ============
         Three-state maps exactly onto the policy model: Enabled writes
         REG_DWORD 1, Disabled writes REG_DWORD 0, Not Configured writes
         nothing and leaves the setting to the device default and then the
         app's built-in floor. There is no registry boolean type; 0/1 is the
         form Bolt reads as a switch. -->
    <policy name="DlpEnabled" class="Machine" displayName="$(string.DlpEnabled)"
            explainText="$(string.DlpEnabled_Help)"
            key="SOFTWARE\Policies\Sparcle\Bolt" valueName="dlpEnabled">
      <parentCategory ref="BoltDesktop" />
      <supportedOn ref="SUPPORTED_BoltDesktop" />
      <enabledValue><decimal value="1" /></enabledValue>
      <disabledValue><decimal value="0" /></disabledValue>
    </policy>

    <policy name="InputGuardEnabled" class="Machine" displayName="$(string.InputGuardEnabled)"
            explainText="$(string.InputGuardEnabled_Help)"
            key="SOFTWARE\Policies\Sparcle\Bolt" valueName="inputGuardEnabled">
      <parentCategory ref="BoltDesktop" />
      <supportedOn ref="SUPPORTED_BoltDesktop" />
      <enabledValue><decimal value="1" /></enabledValue>
      <disabledValue><decimal value="0" /></disabledValue>
    </policy>

    <policy name="PageCaptureEnabled" class="Machine" displayName="$(string.PageCaptureEnabled)"
            explainText="$(string.PageCaptureEnabled_Help)"
            key="SOFTWARE\Policies\Sparcle\Bolt" valueName="pageCaptureEnabled">
      <parentCategory ref="BoltDesktop" />
      <supportedOn ref="SUPPORTED_BoltDesktop" />
      <enabledValue><decimal value="1" /></enabledValue>
      <disabledValue><decimal value="0" /></disabledValue>
    </policy>

    <policy name="VaultRequirePin" class="Machine" displayName="$(string.VaultRequirePin)"
            explainText="$(string.VaultRequirePin_Help)"
            key="SOFTWARE\Policies\Sparcle\Bolt" valueName="vaultRequirePin">
      <parentCategory ref="BoltDesktop" />
      <supportedOn ref="SUPPORTED_BoltDesktop" />
      <enabledValue><decimal value="1" /></enabledValue>
      <disabledValue><decimal value="0" /></disabledValue>
    </policy>

    <policy name="VaultRequireMasterPassword" class="Machine" displayName="$(string.VaultRequireMasterPassword)"
            explainText="$(string.VaultRequireMasterPassword_Help)"
            key="SOFTWARE\Policies\Sparcle\Bolt" valueName="vaultRequireMasterPassword">
      <parentCategory ref="BoltDesktop" />
      <supportedOn ref="SUPPORTED_BoltDesktop" />
      <enabledValue><decimal value="1" /></enabledValue>
      <disabledValue><decimal value="0" /></disabledValue>
    </policy>

    <!-- READ THE HELP TEXT BEFORE ASSUMING NOT CONFIGURED MEANS "LEAVE IT TO
         THE USER". This is the ONE key in this template whose Not Configured
         does not mean that: on any device this template reaches, an unset
         AllowLocalCertificateTrust means DENY. Bolt reads the whole catalogue,
         so a device that carries any Bolt policy at all is a managed device,
         and a managed device does not install root certificates unless its
         administrator says so in writing. -->
    <policy name="AllowLocalCertificateTrust" class="Machine"
            displayName="$(string.AllowLocalCertificateTrust)"
            explainText="$(string.AllowLocalCertificateTrust_Help)"
            key="SOFTWARE\Policies\Sparcle\Bolt" valueName="allowLocalCertificateTrust">
      <parentCategory ref="BoltDesktop" />
      <supportedOn ref="SUPPORTED_BoltDesktop" />
      <enabledValue><decimal value="1" /></enabledValue>
      <disabledValue><decimal value="0" /></disabledValue>
    </policy>

    <!-- ============ In-app updates ============
         Disabled here does not merely hide a button: Bolt does not register
         the update plugin at all, so the app makes no request to the release
         manifest, downloads nothing and installs nothing.

         A value Bolt cannot read (for example a REG_SZ where a REG_DWORD is
         expected) is treated as "updates off", never as "updates allowed" -
         an administrator who wrote one of these keys has asked to govern
         updates, and a typo must not hand the capability back. Not Configured
         is the only thing that leaves updates alone. -->
    <policy name="AppUpdatesEnabled" class="Machine" displayName="$(string.AppUpdatesEnabled)"
            explainText="$(string.AppUpdatesEnabled_Help)"
            key="SOFTWARE\Policies\Sparcle\Bolt" valueName="appUpdatesEnabled">
      <parentCategory ref="BoltDesktop" />
      <supportedOn ref="SUPPORTED_BoltDesktop" />
      <enabledValue><decimal value="1" /></enabledValue>
      <disabledValue><decimal value="0" /></disabledValue>
    </policy>

    <policy name="AppUpdatePinnedVersion" class="Machine"
            displayName="$(string.AppUpdatePinnedVersion)"
            explainText="$(string.AppUpdatePinnedVersion_Help)"
            key="SOFTWARE\Policies\Sparcle\Bolt"
            presentation="$(presentation.AppUpdatePinnedVersion)">
      <parentCategory ref="BoltDesktop" />
      <supportedOn ref="SUPPORTED_BoltDesktop" />
      <elements>
        <text id="AppUpdatePinnedVersion_Text" valueName="appUpdatePinnedVersion"
              required="true" maxLength="64" />
      </elements>
    </policy>

    <!-- ============ Coverage lists (Kind::Coverage) ============
         Merged by UNION across sources: every entry ADDS a place Bolt
         protects, so another authority can widen coverage but never narrow
         what you set here. -->
    <policy name="RiskySites" class="Machine" displayName="$(string.RiskySites)"
            explainText="$(string.RiskySites_Help)"
            key="SOFTWARE\Policies\Sparcle\Bolt"
            presentation="$(presentation.RiskySites)">
      <parentCategory ref="BoltDesktop" />
      <supportedOn ref="SUPPORTED_BoltDesktop" />
      <elements>
        <multiText id="RiskySites_List" valueName="riskySites" required="true"
                   maxLength="16384" maxStrings="512" />
      </elements>
    </policy>

    <policy name="RiskyAppBundleIds" class="Machine" displayName="$(string.RiskyAppBundleIds)"
            explainText="$(string.RiskyAppBundleIds_Help)"
            key="SOFTWARE\Policies\Sparcle\Bolt"
            presentation="$(presentation.RiskyAppBundleIds)">
      <parentCategory ref="BoltDesktop" />
      <supportedOn ref="SUPPORTED_BoltDesktop" />
      <elements>
        <multiText id="RiskyAppBundleIds_List" valueName="riskyAppBundleIds" required="true"
                   maxLength="16384" maxStrings="512" />
      </elements>
    </policy>

    <policy name="InputGuardHosts" class="Machine" displayName="$(string.InputGuardHosts)"
            explainText="$(string.InputGuardHosts_Help)"
            key="SOFTWARE\Policies\Sparcle\Bolt"
            presentation="$(presentation.InputGuardHosts)">
      <parentCategory ref="BoltDesktop" />
      <supportedOn ref="SUPPORTED_BoltDesktop" />
      <elements>
        <multiText id="InputGuardHosts_List" valueName="inputGuardHosts" required="true"
                   maxLength="16384" maxStrings="512" />
      </elements>
    </policy>

    <!-- ============ Exemption lists (Kind::Exemption) ============
         Merged by INTERSECTION: every entry is a HOLE in the policy, so a
         stricter authority can remove your exemptions but never add its own.
         An explicitly EMPTY list is a real value (it closes every hole), which
         is why these are not marked required - see the doc for how to confirm
         an empty box actually wrote an empty REG_MULTI_SZ. -->
    <policy name="AllowedCorpDomains" class="Machine" displayName="$(string.AllowedCorpDomains)"
            explainText="$(string.AllowedCorpDomains_Help)"
            key="SOFTWARE\Policies\Sparcle\Bolt"
            presentation="$(presentation.AllowedCorpDomains)">
      <parentCategory ref="BoltDesktop" />
      <supportedOn ref="SUPPORTED_BoltDesktop" />
      <elements>
        <multiText id="AllowedCorpDomains_List" valueName="allowedCorpDomains" required="false"
                   maxLength="16384" maxStrings="512" />
      </elements>
    </policy>

    <policy name="InputGuardExcludeHosts" class="Machine"
            displayName="$(string.InputGuardExcludeHosts)"
            explainText="$(string.InputGuardExcludeHosts_Help)"
            key="SOFTWARE\Policies\Sparcle\Bolt"
            presentation="$(presentation.InputGuardExcludeHosts)">
      <parentCategory ref="BoltDesktop" />
      <supportedOn ref="SUPPORTED_BoltDesktop" />
      <elements>
        <multiText id="InputGuardExcludeHosts_List" valueName="inputGuardExcludeHosts"
                   required="false" maxLength="16384" maxStrings="512" />
      </elements>
    </policy>

    <policy name="PageCaptureExcludeHosts" class="Machine"
            displayName="$(string.PageCaptureExcludeHosts)"
            explainText="$(string.PageCaptureExcludeHosts_Help)"
            key="SOFTWARE\Policies\Sparcle\Bolt"
            presentation="$(presentation.PageCaptureExcludeHosts)">
      <parentCategory ref="BoltDesktop" />
      <supportedOn ref="SUPPORTED_BoltDesktop" />
      <elements>
        <multiText id="PageCaptureExcludeHosts_List" valueName="pageCaptureExcludeHosts"
                   required="false" maxLength="16384" maxStrings="512" />
      </elements>
    </policy>

    <!-- ============ Ordinary configuration (Kind::Config) ============
         Precedence, forced first. Unlike the enforcement level these can be
         moved in either direction, which is what lets a fleet be rolled
         forward and back. -->
    <policy name="NetworkFilterMode" class="Machine" displayName="$(string.NetworkFilterMode)"
            explainText="$(string.NetworkFilterMode_Help)"
            key="SOFTWARE\Policies\Sparcle\Bolt"
            presentation="$(presentation.NetworkFilterMode)">
      <parentCategory ref="BoltDesktop" />
      <supportedOn ref="SUPPORTED_BoltDesktop" />
      <elements>
        <enum id="NetworkFilterMode_Enum" valueName="networkFilterMode" required="true">
          <item displayName="$(string.NetworkFilterMode_Observe)">
            <value><string>observe</string></value>
          </item>
          <item displayName="$(string.NetworkFilterMode_Enforce)">
            <value><string>enforce</string></value>
          </item>
        </enum>
      </elements>
    </policy>

    <policy name="ShellGovernanceMode" class="Machine" displayName="$(string.ShellGovernanceMode)"
            explainText="$(string.ShellGovernanceMode_Help)"
            key="SOFTWARE\Policies\Sparcle\Bolt"
            presentation="$(presentation.ShellGovernanceMode)">
      <parentCategory ref="BoltDesktop" />
      <supportedOn ref="SUPPORTED_BoltDesktop" />
      <elements>
        <enum id="ShellGovernanceMode_Enum" valueName="shellGovernanceMode" required="true">
          <item displayName="$(string.ShellGovernanceMode_Observe)">
            <value><string>observe</string></value>
          </item>
          <item displayName="$(string.ShellGovernanceMode_Enforce)">
            <value><string>enforce</string></value>
          </item>
        </enum>
      </elements>
    </policy>

    <policy name="BoltUrl" class="Machine" displayName="$(string.BoltUrl)"
            explainText="$(string.BoltUrl_Help)"
            key="SOFTWARE\Policies\Sparcle\Bolt"
            presentation="$(presentation.BoltUrl)">
      <parentCategory ref="BoltDesktop" />
      <supportedOn ref="SUPPORTED_BoltDesktop" />
      <elements>
        <text id="BoltUrl_Text" valueName="boltUrl" required="true" maxLength="2048" />
      </elements>
    </policy>

    <policy name="LaunchMode" class="Machine" displayName="$(string.LaunchMode)"
            explainText="$(string.LaunchMode_Help)"
            key="SOFTWARE\Policies\Sparcle\Bolt"
            presentation="$(presentation.LaunchMode)">
      <parentCategory ref="BoltDesktop" />
      <supportedOn ref="SUPPORTED_BoltDesktop" />
      <elements>
        <enum id="LaunchMode_Enum" valueName="launchMode" required="true">
          <item displayName="$(string.LaunchMode_Native)"><value><string>native</string></value></item>
          <item displayName="$(string.LaunchMode_Popup)"><value><string>popup</string></value></item>
          <item displayName="$(string.LaunchMode_Sidebar)"><value><string>sidebar</string></value></item>
        </enum>
      </elements>
    </policy>

    <policy name="InputGuardMode" class="Machine" displayName="$(string.InputGuardMode)"
            explainText="$(string.InputGuardMode_Help)"
            key="SOFTWARE\Policies\Sparcle\Bolt"
            presentation="$(presentation.InputGuardMode)">
      <parentCategory ref="BoltDesktop" />
      <supportedOn ref="SUPPORTED_BoltDesktop" />
      <elements>
        <enum id="InputGuardMode_Enum" valueName="inputGuardMode" required="true">
          <item displayName="$(string.InputGuardMode_AiSites)">
            <value><string>ai-sites</string></value>
          </item>
          <item displayName="$(string.InputGuardMode_AllSites)">
            <value><string>all-sites</string></value>
          </item>
        </enum>
      </elements>
    </policy>

    <policy name="VaultAutoLockMinutes" class="Machine" displayName="$(string.VaultAutoLockMinutes)"
            explainText="$(string.VaultAutoLockMinutes_Help)"
            key="SOFTWARE\Policies\Sparcle\Bolt"
            presentation="$(presentation.VaultAutoLockMinutes)">
      <parentCategory ref="BoltDesktop" />
      <supportedOn ref="SUPPORTED_BoltDesktop" />
      <elements>
        <enum id="VaultAutoLockMinutes_Enum" valueName="vaultAutoLockMinutes" required="true">
          <item displayName="$(string.VaultAutoLockMinutes_1)"><value><string>1</string></value></item>
          <item displayName="$(string.VaultAutoLockMinutes_5)"><value><string>5</string></value></item>
          <item displayName="$(string.VaultAutoLockMinutes_15)"><value><string>15</string></value></item>
          <item displayName="$(string.VaultAutoLockMinutes_30)"><value><string>30</string></value></item>
          <item displayName="$(string.VaultAutoLockMinutes_Never)"><value><string>0</string></value></item>
        </enum>
      </elements>
    </policy>

    <policy name="VaultMasterPasswordSessionHours" class="Machine" displayName="$(string.VaultMasterPasswordSessionHours)"
            explainText="$(string.VaultMasterPasswordSessionHours_Help)"
            key="SOFTWARE\Policies\Sparcle\Bolt"
            presentation="$(presentation.VaultMasterPasswordSessionHours)">
      <parentCategory ref="BoltDesktop" />
      <supportedOn ref="SUPPORTED_BoltDesktop" />
      <elements>
        <enum id="VaultMasterPasswordSessionHours_Enum" valueName="vaultMasterPasswordSessionHours" required="true">
          <item displayName="$(string.VaultMasterPasswordSessionHours_4)"><value><string>4</string></value></item>
          <item displayName="$(string.VaultMasterPasswordSessionHours_12)"><value><string>12</string></value></item>
          <item displayName="$(string.VaultMasterPasswordSessionHours_24)"><value><string>24</string></value></item>
          <item displayName="$(string.VaultMasterPasswordSessionHours_Restart)"><value><string>0</string></value></item>
        </enum>
      </elements>
    </policy>

    <policy name="VaultPendingMaxHours" class="Machine" displayName="$(string.VaultPendingMaxHours)"
            explainText="$(string.VaultPendingMaxHours_Help)"
            key="SOFTWARE\Policies\Sparcle\Bolt"
            presentation="$(presentation.VaultPendingMaxHours)">
      <parentCategory ref="BoltDesktop" />
      <supportedOn ref="SUPPORTED_BoltDesktop" />
      <elements>
        <enum id="VaultPendingMaxHours_Enum" valueName="vaultPendingMaxHours" required="true">
          <item displayName="$(string.VaultPendingMaxHours_1)"><value><string>1</string></value></item>
          <item displayName="$(string.VaultPendingMaxHours_4)"><value><string>4</string></value></item>
          <item displayName="$(string.VaultPendingMaxHours_24)"><value><string>24</string></value></item>
          <item displayName="$(string.VaultPendingMaxHours_MemoryOnly)"><value><string>0</string></value></item>
        </enum>
      </elements>
    </policy>

  </policies>
</policyDefinitions>
