 深度解析:原生自助服务门户与 Platform SSO 扩展的完整实现)
Fleet Desktop (macOS) 深度解析原生自助服务门户与 Platform SSO 扩展的完整实现【免费下载链接】fleetOpen device management项目地址: https://gitcode.com/GitHub_Trending/fl/fleetFleet Desktop 是 Fleet 为 macOS 终端用户打造的原生自助服务门户应用它以独立.pkg分发bundle IDcom.fleetdm.fleet-desktop通过 WKWebView 在原生窗口中渲染 Fleet 的 Self-service 页面并内嵌实现 Apple Platform SSO v2Password Mode的FleetPSSOExtension.appex扩展。本文基于开源仓库 apps/fleet-desktop-macos 的文档与源码完整讲解它的工作原理、令牌轮换、深度链接、PSSO 扩展、本地构建与 CI/CD 发布流程读完你既能独立构建、签名、部署这个应用也能理解其底层实现机制。一、两个Fleet Desktop先厘清概念在阅读源码前需要先明确Fleet 生态里有两个同名组件。Fleet 的 agentorbit自带一个托盘/菜单栏组件也叫 Fleet Desktopbundle ID 为com.fleetdm.desktop构建自 orbit/cmd/desktop。本文要讲的是另一个独立应用bundle ID 为com.fleetdm.fleet-desktop源码在 apps/fleet-desktop-macos以独立.pkg分发。两者 bundle ID 不同、可以共存。本文讨论的是后者——一个用 Swift AppKit 编写的原生 macOS 应用为终端用户提供设备管理功能的原生窗口替代浏览器访问。二、功能总览与系统要求核心功能功能说明原生 macOS 应用Swift AppKit 实现无 SwiftUI通用二进制同时支持 Apple Siliconarm64与 Intelx86_64自助服务门户WKWebView 内嵌原生窗口无需浏览器内嵌 Platform SSO 扩展实现 IdP 本地账户创建与密码同步Password Mode自动令牌刷新透明处理每小时一次的设备令牌轮换加载画面门户加载期间显示 Fleet logo文件下载支持.mobileconfig配置描述文件及其他 Fleet 下发的文件深色/浅色模式自动跟随系统外观fleet://URL Scheme支持深度链接到 Self-service、Policies触发 refetch、Update/Install allMDM 强制要求应用与安装器均强制要求 MDM 受管代码签名与公证通过.pkg安装器安全分发系统要求macOS 13.0Ventura及以上可运行应用本体PSSO 扩展要求 macOS 14.0其中密码同步功能面向 macOS 26。已启用 MDM 且安装了 Fleet 受管偏好设置的 Mac。已安装并注册 Fleet 的 orbit agent。标识文件必须存在/opt/orbit/identifier。三、工作原理三步走应用的核心逻辑集中在一个类中——FleetDesktop/FleetService.swift读取 Fleet URL从 MDM 受管偏好设置读取见下方配置来源。读取设备令牌从/opt/orbit/identifier读取由 orbit 管理每小时轮换。打开自助服务门户在嵌入式浏览器窗口中加载{FleetURL}/device/{token}/self-service。配置来源文件键用途/Library/Managed Preferences/com.fleetdm.fleetd.config.plistFleetURLFleet 服务器 URL通过 MDM 配置描述文件下发/opt/orbit/identifier—设备认证令牌每小时轮换Fleet Desktop 仅支持 MDM 受管 Mac。若受管偏好设置文件不存在应用会显示错误安装器也会拒绝继续。源码级的配置解析细节FleetService.resolveConfig()FleetService.swift对配置做了严格校验FleetURL必须是HTTPS且带有效 host。源码注释明确指出设备令牌会发送到该 URL若配置了http://令牌将明文暴露在网络上同时URL(string:)能接受无 host 的值如https://若不校验 host构造出的设备 URL 会把字面量路径段device当作 host。令牌读取后会经过字符集白名单校验FleetService.swift只允许 ASCII 字母数字以及-、_。这是为了防止路径分隔符等 URL 元字符进入由令牌构造的 URL。配置校验失败时应用弹出模态错误框NSAlert样式.critical后直接退出。这些细节表明Fleet Desktop 把令牌安全放在了非常高的优先级HTTPS 强制、字符集白名单、令牌不进错误信息是贯穿整个应用的安全设计主线。四、令牌轮换机制60 秒定时器与自动重试orbit 每小时轮换一次/opt/orbit/identifier中的设备令牌。Fleet Desktop 通过三个机制透明处理后台定时器每 60 秒检查一次标识文件tokenRefreshInterval即便窗口关闭、Dock badge 也保持最新。定时器设置了tolerance 5允许系统合并执行以节能并通过ProcessInfo.beginActivity(options: .userInitiatedAllowingIdleSystemSleep)防止 App Nap 在窗口关闭时抑制定时器FleetService.swift。HTTP 401/403 或错误页面检测应用立即重新读取令牌并重试最多 3 次maxRetryAttempts每次间隔 5 秒tokenRetryDelay。对用户不可见页面静默携带新令牌重新加载。handleNavigationError()FleetService.swift的逻辑值得注意Fleet 在令牌过期时可能返回 HTTP 200 但页面内容带错误提示因此BrowserWindow在didFinish回调里注入 JavaScript 检查 DOM 文本FleetErrorPage.matchesExpression命中错误短语即触发令牌刷新流程BrowserWindow.swift。Dock badge 轮询除了令牌应用还每 60 秒调用一次GET {FleetURL}/api/v1/fleet/device/{token}/desktop解析响应中的failing_policies_count把它显示为 Dock 图标角标FleetService.swift。应用还会对比当前 badge 数与已加载页面反映的 badge 数若窗口关闭期间策略失败数变化如从 1 降到 0重新打开窗口时会自动刷新页面reloadIfPoliciesStale()。五、内置浏览器窗口WKWebView 的安全边界窗口由 FleetDesktop/BrowserWindow.swift 实现作为WKNavigationDelegate/WKUIDelegate/WKDownloadDelegate它定义了完整的安全边界非持久化数据存储config.websiteDataStore .nonPersistent()会话之间不保留 cookie 与缓存。ATS 强制 HTTPS嵌入式门户要求 HTTPS。外链白名单外部链接仅允许https、http、mailto三种 scheme其余一律不打开。同源约束同 host 与about:页面始终放行外部链接在默认浏览器打开。SSO 流程检测当 Fleet 服务器重定向到外部 IdP 时进入 SSO 流程状态——外部跳转保留在 WebView 内完成整条重定向链但仅限 HTTPS、仅限当前 IdP host、且流程超时 10 分钟ssoFlowTimeout。跳转到全新外部 host 只能通过服务器重定向或表单提交普通链接点击到无关 host 会转到默认浏览器避免无 chrome 的 WebView 被导向任意站点。流程过期或降级为非 HTTPS 时WebView 会导航回 Fleet 首页而不是滞留在 IdP 页。窗口关闭保活窗口关闭后 WebView 保持存活重新打开瞬间完成。可变状态线程安全所有可变状态当前令牌、重试计数、isSettingUp等由串行派发队列stateQueue保护。文件下载当 Fleet 下发可下载内容如 MDM 注册描述文件时下载判定依据双维度MIME 类型如application/x-apple-aspen-config、application/octet-stream、application/zip等或文件扩展名mobileconfig、pkg、dmg、zip、tar、gz、pdf以及canShowMIMEType为 false 的情况BrowserWindow.swift。.mobileconfig文件下载后自动打开触发安装随后 WebView 导航回 Fleet 自助服务首页。其他所有类型.pkg、.dmg、.zip等保存到~/Downloads不自动打开避免自动执行潜在不安全文件。防覆盖机制若目标文件名已存在自动追加(1)、(2)……上限 999避免覆盖BrowserWindow.swift。同时只取服务端建议文件名的最后路径组件防止路径注入。窗口默认尺寸为min(1100, 屏宽×0.8) × min(750, 屏高×0.8)居中显示最小 480×360位置与大小通过setFrameAutosaveName持久化。六、fleet:// URL Scheme 深度链接Fleet Desktop 注册fleet://URL scheme允许其他工具和脚本打开特定页面。_与-分隔符等价如fleet://install_all与fleet://install-all相同URL动作fleet://self-service打开 Self-service 标签页fleet://software打开 Software 标签页fleet://policies打开 Policies 标签页fleet://refetch触发设备 refetch 并打开应用fleet://update_all打开 Self-service 并点击 Update allfleet://install_all打开 Self-service 并点击 Install allfleet://install_all?category_id##打开按分类过滤的 Self-service 并点击 Install allfleet://anything-else未识别的 URL 仅将应用带到前台命令行示例open fleet://self-service open fleet://refetch open fleet://install_all open fleet://install_all?category_id5源码实现细节handleFleetURL()FleetService.swift的实现有几个亮点合法页面集合是硬编码白名单[self-service, policies, software]其余一律视为仅带到前台。refetch向POST {FleetURL}/api/v1/fleet/device/{token}/refetch发请求成功后延迟 15s 与 30s 各轮询一次 badge以捕获策略变化。Update all / Install all 通过注入 JS 实现应用在页面加载完成后注入一段 JavaScript轮询查找文本为 Update all 或 Install all (N) 的按钮并点击最多重试 60 次、每 500ms 一次。注释明确说明设计意图让安装逻辑继续由 Fleet 的 UI 定义而不是在原生应用里复制一份。其中Install all 只点击触发按钮打开 Fleet 的确认弹窗最终安装必须由用户显式确认——深度链接永远不会在无确认的情况下发起安装。category_id参数校验仅当参数存在、非空且全部为 ASCII 数字时才使用categoryID(from:)防止把意外内容注入到构造的 URL 中。应用未就绪时的待处理状态若 URL 在应用冷启动/设置完成前到达会先存入_pendingPage、_pendingRefetch、_pendingUpdateAll、_pendingInstallAll等状态setup()完成后统一消费。单实例守卫FleetDesktop/FleetDesktopApp.swift 实现了单实例机制后启动的实例通过DistributedNotificationCenter把fleet://深链转发给主实例后立即退出避免出现第二个 Dock 图标。判定标准是同一 bundle ID 下 PID 更小的.regular激活策略实例过滤掉notify这类.accessory无头进程。fleet://handler 在applicationWillFinishLaunching中注册确保捕获系统在启动时投递的 Apple Event。七、Platform SSO 扩展FleetPSSOExtensionFleetPSSOExtension.appex是 Apple 的com.apple.AppSSO.idp-extension实现 Platform SSO v2 的Password Mode。Fleet 服务器提供 IdP 端点扩展将设备密钥注册到 Fleet并通过 Fleet 代理密码登录/密钥交换。扩展被打包在Fleet Desktop.app/Contents/PlugIns/FleetPSSOExtension.appex随同一个.pkg发布。如何绑定到 Fleet 服务器扩展从配置描述文件ExtensionData字典中的单个BaseURL值派生所有端点示例配置见 docs/solutions/macos/configuration-profiles/fleet-sso-extension-example.mobileconfigkeyBaseURL/key stringhttps://fleet.example.com/string在/api/mdm/apple/psso/下派生四个端点AuthenticationViewControllerShared.swift端点方法用途/noncePOST令牌请求的一次性 nonce/registrationPOST设备密钥注册/tokenPOST密码登录 / 密钥请求 / 密钥交换/jwksGETFleet 的 PSSO 公钥applyLoginConfiguration()AuthenticationViewControllerShared.swift会把clientID设为扩展自身 bundle ID、issuer/audience设为 BaseURL 的裸 hostname与 Fleet 签发的iss声明一致并从 Fleet 的 JWKS 拉取标记use:enc的加密公钥设置为loginRequestEncryptionPublicKey使 macOS 在构造登录断言时用 ECDH-ES/A256GCM 加密密码——即使有人能终结 TLS 也读不到密码。BaseURL 必须为 HTTPS因为每个派生端点都携带密钥材料。Fleet 服务器还在https://hostname/.well-known/apple-app-site-association提供 Apple App Site Association 文件包含authsrv条目指明扩展的TeamID.BundleID——即8VBZ3948LU.com.fleetdm.fleet-desktop.pssoextension。关联域为何不烧录进二进制同一个由 CI 构建的通用扩展必须能对接任意Fleet 服务器因此关联域不能固化在二进制里而是权利com.apple.developer.associated-domains以空数组随包分发且com.apple.developer.associated-domains.mdm-managed置为true。实际的authsrv:域即配置的 Fleet 服务器在运行时由 MDM 的AssociatedDomainspayload 投递给扩展的 bundle ID 交付。示例配置中的关联域 payloadfleet-sso-extension-example.mobileconfigdict keyPayloadType/key stringcom.apple.associated-domains/string keyConfiguration/key array dict keyApplicationIdentifier/key string8VBZ3948LU.com.fleetdm.fleet-desktop/string keyAssociatedDomains/key array stringauthsrv:fleet.example.com/string /array /dict dict keyApplicationIdentifier/key string8VBZ3948LU.com.fleetdm.fleet-desktop.pssoextension/string keyAssociatedDomains/key array stringauthsrv:fleet.example.com/string /array /dict /array /dictEntitlements权利宿主应用与扩展都携带受 Apple 管理的受限权利。这些权利不能自由断言——只有捆绑了授予这些权利的 Developer IDprovisioning profile时codesign才会认可见下方签名密钥。BundleEntitlementValueApp 扩展com.apple.developer.associated-domains空数组必须存在App 扩展com.apple.developer.associated-domains.mdm-managedtrue仅扩展com.apple.security.app-sandboxtrue仅扩展com.apple.security.network.clienttrue宿主应用刻意不沙箱化——它需要读取容器外的/opt/orbit/identifier与受管偏好 plist。App Extension 则总是被沙箱化。设备注册流程beginDeviceRegistrationAuthenticationViewControllerPSSO.swift展示了注册的关键步骤若选项含.registrationRepair先调用loginManager.resetDeviceKeys()重置设备密钥——修复场景下重新铸造全新密钥使 keychain、重建的设备配置与服务器保持一致。从loginManager获取sharedDeviceSigning与sharedDeviceEncryption密钥。私钥材料由 Apple 持有扩展只见SecKey句柄仅导出公钥 PEM。校验配置描述文件中的registrationToken非空——Fleet 始终要求注册令牌来注册设备。applyLoginConfiguration先获取服务器加密密钥只有成功后才 POST 注册 payload确保框架不会带着未注册的密钥进入认证流程否则会在 token 端点 404。注册 payload 包含device_uuid、device_signing_key、device_encryption_key、signing_key_id、encryption_key_id、registration_token。keyID是公钥 DER 的 base64url SHA-256AuthenticationViewControllerShared.swift。任一门禁字段导出失败都会拒绝注册而不是提交服务器必然拒绝的不完整 payload。beginUserRegistrationAuthenticationViewControllerPSSO.swift处理用户级绑定保存ASAuthorizationProviderExtensionUserLoginConfiguration缺少它会导致 no user configuration for user、SecureToken 不完整、登录时密钥解包失败 previous password required。无用户名且允许交互时扩展展示原生用户名/密码表单通过 PSSOLoginRequest.swift 构造设备签名的登录 JWS 加密密码断言。完整的示例 MDM 配置描述文件以下配置文件同时包含com.apple.extensiblessoPSSO 配置与com.apple.associated-domains关联域两个 payload可直接参考完整文件?xml version1.0 encodingUTF-8? !DOCTYPE plist PUBLIC -//Apple//DTD PLIST 1.0//EN http://www.apple.com/DTDs/PropertyList-1.0.dtd plist version1.0 dict keyPayloadContent/key array dict keyExtensionData/key dict keyBaseURL/key stringhttps://fleet.example.com/string /dict keyExtensionIdentifier/key stringcom.fleetdm.fleet-desktop.pssoextension/string keyPayloadDisplayName/key stringFleet Extensible Single Sign-On/string keyPayloadType/key stringcom.apple.extensiblesso/string keyPlatformSSO/key dict keyAuthenticationMethod/key stringPassword/string keyUseSharedDeviceKeys/key true/ keyEnableRegistrationDuringSetup/key true/ keyTokenToUserMapping/key dict keyAccountName/key stringaccountName/string keyFullName/key stringname/string /dict /dict keyRegistrationToken/key string$FLEET_VAR_PSSO_DEVICE_REGISTRATION_TOKEN/string keyScreenLockedBehavior/key stringDoNotHandle/string keyTeamIdentifier/key string8VBZ3948LU/string keyType/key stringRedirect/string keyURLs/key array stringhttps://fleet.example.com/string /array /dict /array keyPayloadDisplayName/key stringFleet Platform SSO/string keyPayloadType/key stringConfiguration/string keyPayloadVersion/key integer1/integer /dict /plist其中RegistrationToken使用了 Fleet 的变量语法$FLEET_VAR_PSSO_DEVICE_REGISTRATION_TOKEN实际部署时替换为 Fleet 为设备生成的注册令牌。八、本地构建与开发项目结构仓库中的实际源码结构如下README 中的结构树未包含的 CLI/通知相关文件也一并列出apps/fleet-desktop-macos/ ├── FleetDesktop/ # 宿主应用 │ ├── FleetDesktopApp.swift # App delegate、主菜单、入口点、单实例守卫 │ ├── FleetService.swift # 配置读取、令牌管理、刷新定时器、fleet:// 处理 │ ├── BrowserWindow.swift # WKWebView 窗口、加载遮罩、下载、SSO flow 检测 │ ├── FleetErrorPage.swift # 错误页匹配表达式 │ ├── NotifyCommand.swift # notify 子命令无头通知窗口 │ ├── ToastWindow.swift # 通知吐司窗口 │ ├── cli.swift # CLI 路由与 notify 参数解析 │ ├── Info.plist # App bundle 元数据 │ ├── FleetDesktop.entitlements # 宿主应用权利受管关联域 │ ├── AppIcon.icns # 应用图标 │ └── fleet-logo.png # 加载画面 Fleet logo ├── FleetPSSOExtension/ # Platform SSO 扩展 │ ├── AuthenticationViewController.swift # Principal classSSO 请求处理器 │ ├── AuthenticationViewControllerPSSO.swift # 注册处理器设备/用户注册 │ ├── AuthenticationViewControllerShared.swift # Payload / key-ID / 配置辅助 │ ├── AuthenticationViewControllerNetworking.swift # 对 Fleet 的 URLSession 网络层 │ ├── AuthenticationViewControllerUserRegistration.swift # 交互式用户注册登录表单 → Fleet /token │ ├── PSSOLoginRequest.swift # 设备签名登录 JWS 加密密码断言 │ ├── RegistrationFormView.swift # 原生用户名/密码表单 │ ├── Info.plist # appex 元数据NSExtension 字典 │ └── FleetPSSOExtension.entitlements # 扩展权利 ├── fleet-sso-extension-example.mobileconfig # 示例 com.apple.extensiblesso 配置描述文件 ├── build.sh # 编译通用 app appex └── build-pkg.sh # 生成 .pkg 安装器CI 工作流位于 .github/workflows/fleet-desktop-macos-build.yml。PSSO 扩展以 Foundation app extension 方式用swiftc构建没有main()入口是NSExtensionMainprincipal class 从 appex 的Info.plist加载FleetPSSOExtension.AuthenticationViewController。swiftc的-module-name必须与NSExtensionPrincipalClass中的模块前缀FleetPSSOExtension一致build.sh。本地构建# 构建应用含内嵌扩展 ./build.sh # 运行 open build/Fleet Desktop.app # 构建未签名的 .pkg 安装器 ./build-pkg.shbuild.sh会并行编译 arm64 与 x86_64 两个架构再用lipo合并成通用二进制。swiftc的-target分别为arm64-apple-macos13/x86_64-apple-macos13应用与arm64-apple-macos14/x86_64-apple-macos14扩展扩展的CFBundleShortVersionString/CFBundleVersion会与宿主应用保持同步。要在本地端到端测试用开发签名把 app/扩展部署到本地 Fleet 服务器build.sh接受以下环境变量TEAM_ID、APP_BUNDLE_ID、EXT_BUNDLE_ID、SIGNING_IDENTITY、APP_PROFILE、EXT_PROFILEbuild-pkg.sh接受APP_BUNDLE_ID与INSTALLER_SIGNING_IDENTITY。组合使用即可在非生产 Fleet 开发团队下构建并签名 app .pkg。完整演练签名资产、AASA 覆盖、隧道、配置描述文件与日志见仓库内指南 docs/Contributing/guides/platform-sso-local-development.md。环境变量变量默认值描述ORBIT_ROOT_DIR/opt/orbit覆盖 orbit 目录改变标识文件的读取位置九、CLInotify 子命令应用二进制除了 GUI 模式还内置一个notify子命令cli.swift用于在通知窗口中显示页面FleetDesktop notify --url https url--url必须是带 host 的 HTTPS URLURL 携带设备令牌。--detached-child与--handshake-fd用于父进程派生子进程时的握手管道。未识别的以-开头的参数会落入 GUI 模式macOS 会注入-psn_...参数报错反而会破坏正常启动裸的非破折号词才会被当作子命令。退出码有稳定约定Fleet 服务器将其映射到活动记录0displayed、2usage、30loadFailed、31httpError、41screenLocked、42noDisplay、70internalError。调用脚本本身占用 40、100、101。十、CI/CD构建、签名、公证与发布构建工作流.github/workflows/fleet-desktop-macos-build.yml 在以下时机运行PR 触及apps/fleet-desktop-macos/**、push 到main、手动 dispatch也可作为可复用工作流workflow_call被发布工作流调用。流程为编译 app 与扩展的通用二进制arm64 x86_64并把.appex组装进.app。将 Developer ID provisioning profiles 嵌入 app 与扩展 bundle。由内向外代码签名——先扩展后宿主 app各自携带自己的权利。用自定义 distribution XML 打包成.pkg安装器。用 Fleet 的 Developer ID Installer 证书签名.pkgproductsign。用 Apple 公证notarytool仅显式Accepted状态通过fail-closed并 stapler 加盖票据。将签名后的.pkg作为工作流产物上传保留 30 天。工作流总是签名并公证。无法读取签名密钥的运行如 fork PR、或 provisioning profiles 尚未添加的任何运行会失败而不是产出未签名产物。签名密钥Secrets工作流复用 Fleet 其他 macOS 构建工作流已有的 Developer ID 证书密钥另加两个 provisioning profile 密钥Secret用途APPLE_APPLICATION_CERTIFICATE/..._PASSWORDDeveloper ID Application 证书.p12base64 密码APPLE_INSTALLER_CERTIFICATE/..._PASSWORDDeveloper ID Installer 证书.p12base64 密码APPLE_USERNAME/APPLE_PASSWORD公证用的 Apple ID app-specific 密码APPLE_TEAM_IDApple Developer Team IDKEYCHAIN_PASSWORD临时 CI keychain 密码APPLE_FLEET_DESKTOP_APP_PROFILE_B64com.fleetdm.fleet-desktop的 Developer ID provisioning profilebase64APPLE_PSSO_EXT_PROFILE_B64com.fleetdm.fleet-desktop.pssoextension的 Developer ID provisioning profilebase64Developer ID 证书身份SHA-1固定在工作流env块Application 为604D877399AAEB7630A78B84F288E2D28A2EDE42Installer 为4608F71FB42E1845C7FC9B2D2B6A7A8D11BBD940与 Fleet 的 orbit 和 fleetd-base 构建使用同一团队。Provisioning profiles一次性 Apple Developer 门户设置com.apple.developer.associated-domains*是 Apple 管理的权利没有授予它们的 Developer ID provisioning profilecodesign不会认可。Profile不提交到仓库——它们是与团队/证书绑定的构建输入且会过期所以像.p12证书一样以 base64 secret 存储。在 Fleet 的 Apple Developer 团队8VBZ3948LU下注册两个 App IDcom.fleetdm.fleet-desktop宿主应用与com.fleetdm.fleet-desktop.pssoextension扩展。在两个 App ID 上启用Associated Domains与MDM Managed Associated Domains能力。为每个 App ID 创建Developer IDprovisioning profiledistribution平台 macOS。必须选择 CI 签名用的同一张 Developer ID Application 证书——即 SHA-1604D877399AAEB7630A78B84F288E2D28A2EDE42。Fleet 有多张 Developer ID Application: Fleet Device Management Inc 证书用错误证书生成的 profile 能签名并通过公证但启动时会被 AMFI SIGKILL因为 AMFI 要求签名证书出现在 profile 的DeveloperCertificates数组中。工作流里的Verify profiles authorize the signing certificate步骤专门拦截这种情况。将下载的.provisionprofilebase64 编码后存为两个 secretbase64 -i FleetDesktop_DeveloperID.provisionprofile | pbcopy # → APPLE_FLEET_DESKTOP_APP_PROFILE_B64 base64 -i FleetPSSOExtension_DeveloperID.provisionprofile | pbcopy # → APPLE_PSSO_EXT_PROFILE_B64Profile 过期或签名证书轮换时需重新编码并更新 secret。检查 profile 的权利与授权证书security cms -D -i profile.provisionprofileDeveloperCertificates数组必须包含上面的 CI 签名证书。发布流程发布由release-fleet-desktop-macos.yml工作流驱动README 指向它构建工作流头注释确认它通过workflow_call复用构建流程发布到https://download.fleetdm.com/fleet-desktop-macos/vversion/。版本不可变——已存在于 download.fleetdm.com 的版本不能覆盖。不创建 GitHub Releasegit tag 即发布标记。在FleetDesktop/Info.plist中提升CFBundleShortVersionString及CFBundleVersion并合并到main。打 tag 并推送git tag fleet-desktop-macos-vversion git push origin fleet-desktop-macos-vversion在 Actions 页签运行Release Fleet Desktop (macOS)在 Use workflow from 下拉中选择该 tag。工作流在以下情况会在构建前失败所选 ref 不是main上的fleet-desktop-macos-v*tag、tag 版本与Info.plist不匹配、或该版本已上传。构建成功后上传 pkg 与meta.json含version、fleet_desktop_pkg_sha256、fleet_desktop_pkg_url再从公网 URL 下载 pkg 校验 SHA256 通过后才算成功。testing输入会上传到download-testing.fleetdm.com而非生产环境——改完工作流后的首次运行建议使用它。十一、安装与部署方式签名并公证的.pkg由 CI 产出并作为工作流产物上传。部署方式有两种通过 FleetSoftware把.pkg作为软件安装器上传到 FleetFleet Desktop 会出现在软件目录中供部署。手动安装双击.pkg跟随安装器向导。安装器要求 MDM 受管 Mac会先检查 Fleet 受管偏好设置 profile——未找到则显示错误并中止。应用安装到/Applications属主root:admin、权限755。升级时安装器会先优雅退出 Fleet Desktop安装完成后自动重新启动。把 app 装入/Applications同时也是注册内嵌FleetPSSOExtension.appex的方式使其可被com.apple.extensiblesso配置描述文件选择。总结从架构上看Fleet DesktopmacOS是一个原生壳 一个系统扩展的清晰组合原生壳解决终端用户访问自助服务门户的体验问题原生窗口、深链、通知、令牌轮换PSSO 扩展则把 Fleet 变成 macOS 账户生命周期的一部分IdP 驱动的本地账户创建与密码同步。两者共享同一条安全主线——令牌与密钥永不落日志、HTTPS 强制、受限权利由 provisioning profile 授权、安装逻辑始终由 Fleet 的 UI 决策。对于想自建类似设备自助门户 平台级 SSO方案的团队这份源码是相当完整且有工程参考价值的实现范本。项目许可证为 MIT Expat见仓库根目录 LICENSE。【免费下载链接】fleetOpen device management项目地址: https://gitcode.com/GitHub_Trending/fl/fleet创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考