Deployment sources
理解本地目录、Git 仓库、镜像、Compose 和静态站点如何成为部署输入。
部署来源回答“要部署什么”。它可以是本地目录、Git 仓库、Docker 镜像、Compose 清单或静态站点输出。
这个输入不应该承担项目、服务器、环境或域名的职责。Appaloft 会在 detect 阶段读取来源证据,并在 plan 阶段生成可解释的运行计划。
已有入口应该把 Web、CLI 和 HTTP API 的 source 解释成同一个概念。Web 里的 source 字段、CLI 的 positional source 或 --source、API 的 source input 都应该指向这里,而不是各自定义一套含义。
常见来源类型:
| 类型 | 适合场景 | 用户需要确认 |
|---|---|---|
| 本地目录 | CLI 本地部署、快速试验。 | 当前目录、忽略文件、构建输出。 |
| Git 仓库 | 可重复部署、CI、preview。 | 仓库 URL、ref、子目录、访问权限。 |
| Docker/OCI 镜像 | 已经有构建产物。 | 镜像地址、tag、运行端口。 |
| Compose 清单 | 多容器或已有 Compose 配置。 | compose 文件路径、服务名、暴露端口。 |
| 静态站点 | 前端静态产物。 | 构建命令和 publish directory。 |
用户不确定时,应先选择最接近当前交付物的来源。后续 runtime profile 会描述如何运行它。
用户应能看到来源是否可读取、ref 或路径是否存在、静态输出目录是否明确,以及来源和资源 runtime profile 是否明显冲突。
Web console 应在提交前提示缺失字段,例如 Git ref、base directory 或静态输出目录。CLI 应把无法读取路径、无法访问仓库、空 source 等问题作为输入错误。HTTP API 应返回结构化 validation error,包含字段名和恢复建议。
CLI source 示例:
appaloft deploy ./apps/web --method static --publish-dir buildappaloft deploy ./dist --as static-siteappaloft deploy https://github.com/example/web \
--method static \
--publish-dir dist \
--resource-name web资源 source profile 示例:
appaloft resource configure-source res_web \
--kind git-repository \
--locator https://github.com/example/web \
--git-ref main \
--base-directory apps/web当用户已经有 dist、build 或类似静态输出目录时,可以把这个目录作为 source 直接交给 Appaloft:
appaloft deploy ./dist --as static-site这个入口只改变用户层交互:它会归一化为静态站点资源和普通部署请求,不会新增 quick-deploy.create 操作,也不会把目录上传到 Appaloft 托管云。除非用户显式选择托管功能,部署目标仍然是用户选择的服务器或环境。
部署被接受后,source 会进入部署快照。后续修改资源 source profile 不会改变已经完成或正在执行的部署。
用户应能在部署详情里看到安全的 source 摘要,例如 repository、ref、base directory、镜像 tag 或静态输出目录。Secret token、私有仓库凭据和完整本地路径中的敏感片段不应出现在日志或诊断摘要中。
常见恢复方式:
- 本地目录不存在:确认 CLI 当前工作目录或传入绝对路径。
- Git 仓库不可访问:确认凭据、仓库 URL、ref 和网络。
- 静态输出目录为空:确认 build 命令已经生成产物。
- 来源和 runtime profile 不匹配:调整资源 runtime profile,或换成更合适的 source kind。
如果资源已经绑定过旧来源,使用 Deployment recovery 重新关联。
Source auto-deploy 会把已验证的 source event 转换为普通部署请求,但不会把 branch、webhook 或
delivery id 塞进 deployments.create。第一条已启用的 ingestion route 是 Resource-scoped generic
signed webhook:
POST /api/resources/{resourceId}/source-events/generic-signed启用时,策略属于一个 Resource,并绑定到该 Resource 当前的 source profile。修改 Resource source 后,旧策略会进入 blocked 状态,直到用户显式确认新 source 仍然应该触发自动部署。
Git provider webhook 和 generic signed webhook 都必须先完成签名校验,再进入 policy matching。
generic signed webhook 使用 X-Appaloft-Signature,格式可以是 sha256=<hex> 或裸 HMAC
SHA-256 hex。策略里的 secret reference 必须是 resource-secret:<KEY>,其中 <KEY> 是同一个
Resource 上的 runtime secret variable。Appaloft 只保存安全的 reference metadata,不保存 secret
明文、签名 header 或 raw payload。
轮换 secret 时,应先替换底层 secret reference,再按需要重新确认自动部署策略。
Source event 会先写入 durable record,再尝试创建部署。重复投递使用 provider delivery id、 generic idempotency key,或 source/ref/revision/event kind 的 bounded-window key 去重。generic signed route 的去重范围限定在 route Resource。
重复事件不会创建第二个部署。用户应能在 source event read model 中看到 deduped 状态和原始
source event id。
已验证的事件也可能不创建部署。常见原因包括 ref 不匹配、没有启用的策略、策略被禁用、或 source binding 变化后策略处于 blocked pending acknowledgement。
这些结果应该通过 source-events.list 和 source-events.show 显示安全的 reason code、匹配的
Resource、以及已创建的 deployment id。不要在日志或 UI 中暴露 webhook secret、provider token 或
raw payload。
第一版 ingestion path 会记录 source event state 和同步 dispatch 结果,不承诺后台自动重试。若事件 dispatch 失败,先查看 source event detail,再根据情况修复 source profile、secret reference、策略状态或 运行时阻塞。
修复后可以用 appaloft source-event replay <sourceEventId> --resource <resourceId> 或
POST /api/source-events/{sourceEventId}/replay 重放已保留的 safe delivery facts。Replay
会重新按当前 Resource policy 匹配并走普通 deployments.create admission;它不会读取 raw
webhook payload、signature、provider token 或 webhook secret。
如果部署已被创建,后续恢复应使用普通 deployment recovery/readiness、retry、redeploy 或 rollback 语义,而不是重放 webhook payload。
使用 appaloft source-event prune --before <iso> 或 POST /api/source-events/prune 先检查已保留的
source event delivery。Prune 默认 dry-run,并返回按 status 和 source kind 分组的匹配数量。只有在确认
scope 和 cutoff 后,才传入 --dry-run false 执行清理。
Retention cleanup 只删除已持久化的安全 source event 诊断记录。它不会删除 Resource、deployment、 webhook secret、provider token、raw payload,也不会影响 cutoff 和 filter 之外事件的 replay 能力。