ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Fleet-maintained apps 全链路解析:Fleet 如何让应用目录安全且保持最新

2026/9/19 3:56:20 拓冰建站 浏览量
Fleet-maintained apps 全链路解析:Fleet 如何让应用目录安全且保持最新 Fleet-maintained apps 全链路解析Fleet 如何让应用目录安全且保持最新【免费下载链接】fleetOpen device management项目地址: https://gitcode.com/GitHub_Trending/fl/fleetFleet 应用目录Fleet-maintained apps中的每一款应用都经过从厂商官方地址直连下载、按固定哈希校验、在真实硬件上完整安装/卸载验证、由人工审阅四道关卡才会抵达你的主机。本文基于 Fleet 开源仓库的清单、生成器、验证器与 CI 工作流逐层拆解这条从厂商发版到主机部署的供应链管道并给出添加新应用、冻结坏版本、配置补丁策略的完整实操。核心要点安装包直接来自厂商Fleet 从不二次托管或修改安装包Fleet 服务器从厂商官方分发地址下载应用并在存储前校验其 SHA-256 哈希。目录自我更新自动化每 4 小时检查一次上游包源macOS 的 Homebrew casks、Windows 的 winget manifests厂商发版当天即可成为更新候选。未经测试不发布目录的每一次变更都会先在真实的 macOS 与 Windows 主机上执行完整的安装/卸载生命周期验证再由 Fleet 团队成员审阅合并。坏更新会被冻结而非发布若新版本验证失败Fleet 将该应用保持在最后一个可用版本并记录 bug绝不让坏更新替换好版本。主机无需人工盯守即可保持最新应用默认追踪最新已验证版本你也可以固定版本进行变更控制补丁策略patch policies会自动修复运行过期软件的主机。全程可审计应用清单、安装/卸载脚本全部开源你可以直接阅读主机上实际运行的每一条命令并查看每一次变更的历史。目录从何而来上游元数据 4 小时自动摄取Fleet 并不自行维护每个应用在哪里的记录。元数据来自被数百万开发者信赖的上游源macOS 使用 Homebrew casks 中定义由schedule的 cron 表达式0 */4 * * *驱动即每 4 小时运行一次同时也支持workflow_dispatch手动触发以及ee/maintained-apps/**路径变更时的 push 触发。工作流的执行逻辑很直接检出仓库、安装 Go 环境运行go run cmd/maintained-apps/main.go摄取器会对比上游最新的版本、下载 URL 与 SHA-256 哈希若有变化用peter-evans/create-pull-request打开一个名为 Update Fleet-maintained apps 的 PR更新应用版本、下载 URL、哈希并重新生成安装/卸载脚本自动关闭之前已存在、但已被本次新 PR 取代的旧 PR。新应用进入目录的路径相同Fleet 团队成员或社区贡献者编写一个输入清单input manifest发起 PR。生成器与验证器的入口都在 cmd/maintained-apps/main.go核心数据结构FMAManifestApp、FMAManifestFile等定义在 ee/maintained-apps/maintained_apps.go。在真实主机上验证装、验、卸的完整生命周期任何变更合并前自动化测试都会下载被变更的应用在真实硬件上走完完整生命周期安装它 → 确认应用确实存在于主机上 → 卸载它并确认已彻底消失。macOS 应用在 macOS 主机上验证Windows 应用则在 x64 或 Arm 主机上验证以匹配安装器架构。验证由两个矩阵化的可复用工作流驱动macOS.github/workflows/test-fma-darwin.yml 先在廉价的 Linux runner 上把所有 darwin 应用切分成 shard默认每片 25 个再扇出到 macOS runner 并行验证。因为 GitHub 对 macOS 并发任务有上限超出上限的 shard 会排队分波运行。Windows.github/workflows/test-fma-windows.yml 按安装器架构做分区——arm64应用路由到windows-11-armrunnerx64/x86/neutral应用路由到 x64 runner标记了requires_client_os的应用永远走windows-11-arm因为 x64 runner 是 Windows Server。每个 shard 的实际验证逻辑在 test-fma-darwin-validate.yml 与 test-fma-windows-validate.yml 中。值得注意的细节包括runner 镜像预装了一些目录中的应用Chrome、7-Zip、Firefox、Node.js、PowerShell、R、Git 等验证前会先卸载干净确保从干净状态开始验证darwin 验证器先安装 osquery 5.18.1 用于查询应用是否存在Windows 验证通过go run -buildvcsfalse ./cmd/maintained-apps/validate执行且刻意在移除预装 Git之后再跑此时 runner 上已无 git故需关闭 VCS 烙印。真正的验证程序是 cmd/maintained-apps/validate/main.go含darwin.go、windows.go与app_commander.go三个平台/执行模块它依据ee/maintained-apps/outputs/apps.json逐个应用执行下载 → 安装 → 校验存在 → 卸载 → 校验消失。通过的变更仍不会自行合并——Fleet 团队成员会审阅每一个 PR 后才发布。失败的变更则根本不会发布Fleet 将应用冻结在最后一个成功安装的版本并记录 bug。冻结有一个诚实的权衡如果厂商在冻结期间删除了旧版本的下载链接那么该应用的安装会失败直到 Fleet 发布修复版本。团队认为这比静默发布一个我们无法验证的更新要好得多。验证通过的硬性标准ee/maintained-apps/README.md 明确列出了每个被更新应用必须独立满足的四条验收标准应用可通过清单中的 URL 下载应用可通过清单中的安装脚本在主机上成功安装应用确实存在于主机上应用可通过清单中的卸载脚本在主机上成功卸载。只要有一条不满足就进入冻结 记录 bug流程。生命周期一览主机上的应用如何保持更新一旦变更发布你的 Fleet 服务器会自动拾取。服务器每小时刷新一次目录或在你运行fleetctl trigger --namemaintained_apps时立即刷新。你无需升级 Fleet 就能获得新应用或新版本。这个每小时刷新在服务端有对应的定时任务常量定义见 server/fleet/cron_schedules.go 中的CronMaintainedApps值为maintained_apps。此外还有两个相关的 cronCronMaintainedAppsAutoUpdatemaintained_apps_auto_updatePremium 功能每小时运行一次把每个 FMA 的活动安装器推进到其固定状态允许的最新缓存版本CronWindowsMaintainedAppTitles把报告名称中内嵌版本号的 Windows 软件标题合并到 FMA 安装器所拥有的标题下。服务端拉取远程清单并写入本地库的核心逻辑在 server/mdm/maintainedapps/sync.go。其中的Hydrate函数sync.go 第 174 行起负责把应用级 FMA 清单中的信息灌入从数据库取出的 FMA 骨架若指定了版本且有缓存优先从本地缓存加载安装器级字段版本、平台、下载 URL、SHA-256、安装/卸载脚本、补丁查询等缓存未命中时回退到远程清单——这样刚发布、尚未缓存的版本例如管理员在单次 GitOps apply 中固定到某个刚发布的最新版也能被水合并下载若请求的版本在当前已发布清单中也不存在则返回 version not available 错误。默认情况下Fleet-maintained apps 追踪最新已验证版本。厂商发布更新后Fleet 会在新安装时使用它无论主机是通过自助服务、手动安装还是策略自动化安装应用运行旧版本的主机都会在下次安装时升级到最新版。如果你的变更控制流程需要更强的可预测性可以把应用固定到特定版本或主版本即 pin a version如果某个更新引入了 bug也可以通过固定到上一版来回滚。补丁策略闭环的最后一环补丁策略patch policies负责收网落后主机。从应用的详情页进入Actions Deploy启用PatchFleet 就会生成一条检测运行过期版本主机的策略。要启用安装自动化选择Patch when app is closed或Force patch。之后可在Actions Deploy或Policies [policy] Edit policy Patch处修改。补丁策略的查询会每小时自动更新为引用最新版本或在你应用 GitOps 配置时更新所以策略永远不会过期。最终形成一条无手动环节的链路厂商发布 → Fleet 验证并发布 → 你的服务器同步 → 你的主机自我修复。安全模型目录的安全建立在几条朴素承诺之上厂商直连下载Fleet 从不重新托管或修改安装包。添加或更新应用时你的 Fleet 服务器从厂商官方分发 URL 下载安装器——与你自己去下载是同一个地址。固定哈希每个应用版本都记录了上游包清单中发布的 SHA-256 哈希Fleet 服务器会拒绝任何不匹配的下载。部分厂商只发布无法预先固定的滚动 latest URL对这些应用Fleet 改为在下载时记录安装器的哈希。端到端开源每一份清单、安装脚本和卸载脚本都存在于公开的 Fleet 仓库中每一次变更都以附带验证结果的 PR 形式到达。你无需猜测某个 FMA 会在主机上运行什么——直接去读就好。从数据结构上看哈希与脚本确实以逐版本 去重引用的方式组织在输出清单中。以 ee/maintained-apps/outputs/7-zip/windows.json 为例每个版本记录installer_url、sha256、install_script_ref与uninstall_script_ref而脚本正文则集中存放在同文件的refs映射里引用键由 ee/maintained-apps/maintained_apps.go 中的GetScriptRef函数取脚本 SHA-256 的前 8 个十六进制字符生成——同一脚本多处复用不重复存储。以 7-Zip 的 Windows 清单为例可以看到三个关键查询与安装/卸载脚本引用{ version: 26.03, queries: { exists: SELECT 1 FROM programs WHERE name LIKE 7-Zip % AND publisher Igor Pavlov;, patched: SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM programs WHERE name LIKE 7-Zip % AND publisher Igor Pavlov AND version_compare(version, 26.03) 0);, open: SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM processes WHERE LOWER(name) IN (7zfm.exe,7zg.exe)); }, installer_url: https://www.7-zip.org/a/7z2603-x64.msi, sha256: c0680064d698a62dd4a5a47f403db356a6531a5473e4c4b1d090ea2590513926, upgrade_code: {23170F69-40C1-2702-0000-000004000000} }这三条 osquery 查询分别回答应用是否存在exists、应用是否已打过补丁patched、应用是否正在运行open是策略与补丁逻辑的判断基础。如果你在 Fleet-maintained app 中发现疑似安全问题请通过 Fleet 的漏洞披露计划见仓库根目录 SECURITY.md报告。服务级别目标SLO以下是 Fleet 为目录设定的自我约束目标活动目标检查上游包源是否有新版本每 4 小时检测到新版本后发布已验证的应用更新1 个工作日内客户 Fleet 服务器拾取已发布的目录变更1 小时内审阅新增应用的社区 PR3 个工作日内为目录贡献新应用任何人都可以提议一个新的 Fleet-maintained app。分步说明见 ee/maintained-apps/README.md。提交的应用会与目录中的其他内容一样接受相同的自动化验证并由 Fleet 工程经理在 3 个工作日内审阅。macOS 应用输入清单与生成命令在 Homebrew formulae{ name: Box Drive, slug: box-drive/darwin, unique_identifier: com.box.desktop, token: box-drive, installer_format: pkg, default_categories: [Productivity] }macOS 输入清单的核心字段名称类型说明namestring必填。面向用户的应用程序名称。unique_identifierstring必填。平台特有的唯一标识macOS 上即 bundle identifier。tokenstring必填。Homebrew 的唯一标识即 Homebrew API 响应中的token字段。installer_formatstring必填。安装包文件格式zip、dmg、pkg通过 Homebrew APIurl字段的文件扩展名判断若无扩展名则下载安装包确认。slugstring必填。标识应用/平台组合如box-drive/darwin格式app-name/platform用于命名清单文件并在 Fleet 的 GitOps 配置中引用该应用。default_categoriesstring必填。自助服务未指定分类时的默认分类合法值为Browsers、Communication、Developer Tools、Productivity。pre_uninstall_scriptsstring在生成的卸载脚本之前运行的命令行见 Box Drive 示例中的 File Provider 域清理与 sudoers 处理。post_uninstall_scriptsstring在生成的卸载脚本之后运行的命令行。install_script_pathstring自定义安装脚本.sh路径覆盖生成的安装脚本脚本必须放在inputs/homebrew/scripts/。uninstall_script_pathstring自定义卸载脚本.sh路径覆盖生成的卸载脚本不能与pre_uninstall_scripts/post_uninstall_scripts同时使用。cask_pathstring本地 cask JSON 文件的仓库相对路径用于第三方 tap见下。Box Drive 的输入清单展示了pre_uninstall_scripts/post_uninstall_scripts的真实用法卸载前通过fileproviderctl与 Box 的streem工具移除 File Provider 域区分归档未同步内容与保留未同步内容两种模式删除com.box.desktop的偏好设置并在/etc/sudoers.d/写入临时 sudoers 规则以便调用厂商卸载器卸载后清理该文件。自定义 tap 的应用摄取位于第三方 Homebrew tap非Homebrew/homebrew-cask中的应用不会被https://formulae.brew.sh/api/代理。要摄取它们需把.rb源文件和生成的.json一起提交到ee/maintained-apps/inputs/homebrew/custom-tap/按 Homebrew tap 的目录布局组织custom-tap/ ├── Casks/token.rb # Cask DSL source ├── api/token.json # Generated with regenerate.sh └── regenerate.sh # Rebuild api/*.json from Casks/*.rb流程为编写 cask DSL → 在custom-tap/内运行./regenerate.sh生成api/token.json需 macOS Homebrew jq→ 在输入清单中把cask_path设为ee/maintained-apps/inputs/homebrew/custom-tap/api/token.json。未设置cask_path的应用继续从formulae.brew.sh抓取。Windows 应用输入清单与生成命令在 winget-pkgs 清单中找到PackageIdentifier后先在测试 Windows 主机上手动安装该应用再运行对应的 PowerShell 查询获取 Fleet 用于软件清单匹配的unique_identifier即注册表中的DisplayName机器级安装machine scopeGet-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* -ErrorAction SilentlyContinue | Where-Object {$_.DisplayName -like *App Name*} | Select-Object DisplayName, DisplayVersion, Publisher用户级安装user scopeGet-ItemProperty HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* -ErrorAction SilentlyContinue | Where-Object {$_.DisplayName -like *App Name*} | Select-Object DisplayName, DisplayVersion, Publisher关键提示如果unique_identifier与DisplayName不匹配Fleet 会在 FMA 添加并安装后错误地创建两个软件标题——一个是 FMA另一个是清单库中的软件。然后填写输入清单例如 ee/maintained-apps/inputs/winget/box-drive.json{ name: Box Drive, slug: box-drive/windows, package_identifier: Box.Box, unique_identifier: Box, installer_arch: x64, installer_type: msi, installer_scope: machine, default_categories: [Productivity] }Windows 输入清单的核心字段名称类型说明namestring必填。面向用户的应用程序名称。unique_identifierstring必填。平台特有的唯一标识Windows 上即DisplayName。package_identifierstring必填。winget 的PackageIdentifierFleet 据此拉取正确的应用元数据。slugstring必填。应用/平台组合标识如box-drive/windows。installer_archstring必填。x64、x86或arm64多数应用为x64。ARM64 构建是独立的 FMAslug 带-arm64后缀、名称带(ARM64)后缀如firefoxnightly-arm64/windowsCI 在windows-11-armrunner 上验证。installer_typestring必填。exe、msi或msix指文件类型而非厂商技术如 wix。installer_scopestring必填。machine或user受管安装优先machine。default_categoriesstring必填。默认分类合法值同上。install_script_pathstring自定义安装脚本.ps1路径必须放在inputs/winget/scripts/。.msi应用由摄取器自动生成安装脚本除非要覆盖生成行为否则不要添加.exe应用必须提供直接运行安装器的 PowerShell 脚本Fleet 在安装时把安装包发给主机脚本必须通过INSTALLER_PATH环境变量执行它。uninstall_script_pathstring自定义卸载脚本.ps1路径。.msi应用自动生成.exe应用需按厂商文档的静默卸载开关或注册的 UninstallString 编写确保静默运行并返回安装器退出码。fuzzy_match_nameboolean当unique_identifier与DisplayName不匹配时设为true让 Fleet 用模糊匹配把 FMA 与清单库软件对应起来如 Pritunl 的unique_identifier是 Pritunl而清单库DisplayName是 Pritunl Client。requires_client_osboolean安装器拒绝在 Windows Server SKU 上运行时设为true如 Dell Display and Peripheral Manager。CI 据此把验证路由到windows-11-armrunnerGitHub 托管的唯一客户端 OS Windows runner而不是默认的 Windows Server x64 runner。运行生成器并提交在仓库根目录运行以下命令生成输出数据go run cmd/maintained-apps/main.go --slugapp-name/darwin --debug # 或 go run cmd/maintained-apps/main.go --slugbox-drive/windows --debug贡献者还需负责把应用图标加入 FleetTypeScript 与网站 PNG 组件图标由tools/software/icons下的 generate-icons 脚本生成脚本会自动在frontend/pages/SoftwarePage/components/icons/index.ts中添加 import 语句和 map 条目无需手动更新索引文件。之后在ee/maintained-apps/outputs/apps.json中为应用补充描述macOS 可借用 Homebrew formulae 的描述采用句子式大小写格式为App Nameis a(n) ...以.结尾。最后打开 PR工程经理会被自动添加为 reviewer同时需 提及 FMA 的负责人若涉及新图标还应 提及产品设计师做第二双眼睛。Windows 常见问题排查ee/maintained-apps/README.md 还收录了几条高频故障的排查方向Fleet UI 中找不到应用确认apps.json已由生成器更新且你的覆盖 URL 正确安装静默失败确认installer_type、installer_arch、installer_scope与所选 winget 安装器一致并在测试主机上手动运行你的 PowerShell 脚本卸载不干净优先使用显式卸载脚本否则确保 winget 清单暴露了ProductCode或UpgradeCode哈希不匹配错误若上游清单仍在变动可在输入 JSON 中设置ignore_hash: true谨慎使用。在 macOS 上也可以做以上 Windows 流程本意是在 Windows 主机上运行但大部分也可以在 macOS 上完成摄取器是 Go 代码从 winget/GitHub 抓取数据跨平台可用PackageName与Publisher可以在 winget-pkgs 仓库的 locale 和 installer yaml 文件中查找。只有验证与测试阶段仍需要 Windows 主机用于确认programs.name以及真实运行安装/卸载。更新与冻结既有应用Fleet-maintained apps 需要尽可能频繁地更新同时保持可靠性这目前是一个平衡行为因为两种情形都会造成阻塞客户工作流的 bug厂商对安装器的更新可能破坏安装/卸载脚本厂商会弃用旧安装器的下载链接。GitHub Action 会周期性创建 PR通过提升版本 重新生成安装/卸载脚本来更新目录中的一个或多个应用。PR 中每个被更新的应用都必须独立验证只有全部满足前述四条验收标准才可合并。若某应用未通过则执行冻结流程不要按原样合并该 PR在失败应用的输入文件中加入frozen: true如inputs/homebrew/app.json把对应的输出清单如outputs/slug.json回退到main分支版本git checkout origin/main -- ee/maintained-apps/outputs/slug.json运行go run cmd/maintained-apps/main.go --slugslug --debug验证冻结后的输入文件——应无报错且不产生任何变更将输入变更与输出回退提交到同一个 PR。信任但要验证软件供应链攻击之所以得逞是因为多数更新管道是不可见的——你无法审计你看不见的东西。Fleet 的答案是让从厂商发布到主机安装的整条路径公开数据源、脚本、测试、审阅。这些承诺全部落在仓库本身清单在 ee/maintained-apps/inputs/Homebrew 与 winget 两份输入与 ee/maintained-apps/outputs/生成的输出与脚本引用摄取与验证工作流在 .github/workflows/ingest-maintained-apps.yml、test-fma-darwin*.yml、test-fma-windows*.yml生成器与验证器在 cmd/maintained-apps/服务端同步与水合逻辑在 server/mdm/maintainedapps/。不要只听 Fleet 说——仓库是开放的PR 历史也是。参考与延伸ee/maintained-apps/README.md贡献新应用的完整分步指南macOS/Windows 输入清单、冻结流程、自定义 tap 摄取。.github/workflows/ingest-maintained-apps.yml每 4 小时自动摄取并开 PR 的 CI。.github/workflows/test-fma-darwin-validate.yml 与 .github/workflows/test-fma-windows-validate.yml真实主机安装/卸载验证。cmd/maintained-apps/main.go 与 cmd/maintained-apps/validate/main.go摄取生成器与验证器。server/mdm/maintainedapps/sync.go服务端目录刷新与版本水合。server/fleet/cron_schedules.gomaintained_apps等定时任务定义。实战延伸在应用详情页通过Actions Deploy添加应用并启用Patch补丁策略需要变更控制时把应用固定到特定版本GitOps 用户可在配置中直接引用fleet_maintained_apps条目参见 cmd/fleetctl/fleetctl/templates/new/fleets/workstations.template.yml 的示例。【免费下载链接】fleetOpen device management项目地址: https://gitcode.com/GitHub_Trending/fl/fleet创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考