# 套件上传与发布后台协议 v1.0（预定接口）

**本文件为后续独立后台的实施合同，下列接口当前尚未部署。** NAS用户端与开发者/审核管理后台分开。后台建议使用 Rust；管理后台不能获取NAS登录账户、sudo密码或业务数据。包格式见 [SPKG-SPEC.md](SPKG-SPEC.md)。

## 身份与权限

独立后台会话/OIDC身份验证，开发者提交与审核/发布角色分离。`packages.submit` 只能管理本人草稿；`packages.review` 可审核且不能自审；`packages.publish` 可发布已批准版本；`sources.manage` 管理源信任。上传token短时有效、scope限定，CSRF/审计/请求限流必须实现。私钥由签名服务/KMS保管，不能下发给前端或存储在Git。

## 上传与审核流程

`draft → uploaded → validating → review_pending → approved → published`；失败为 `validation_failed`，审核拒绝为 `rejected`。已发布包只能撤回（`withdrawn`），不可覆盖。包tuple为 pkg_id/version/排序后的architecture集合，开发者必须拥有该 pkg_id 的授权，不能抢占官方命名空间。

| 方法与路径（/admin/v1前缀） | 合同 |
| --- | --- |
| POST /packages/uploads | JSON声明 filename、size、sha256；返回 upload_id、受限临时上传地址、expires_at；Idempotency-Key 去重 |
| PUT /packages/uploads/{id}/content | application/octet-stream；分块流式写入隔离存储，强制总大小/超时，返回202与验证job_id；禁止用户指定服务器路径 |
| GET /packages/uploads/{id} | 本人/审核角色可见；状态、已收字节、校验结果、manifest、错误字段路径 |
| GET /jobs/{id} | 状态/阶段/有界脱敏日志，GET /jobs/{id}/events 提供 SSE；不伪造下载/扫描百分比 |
| POST /packages/uploads/{id}/submit | 校验通过后提交审核；JSON含release_notes；元数据不可修改成与归档不一致 |
| GET /reviews | 有审核权限的待审列表，游标分页、架构/类别筛选 |
| POST /reviews/{id}/decision | approve/reject +原因 +expected_revision；拒绝自审与过期状态 |
| POST /releases | upload_id +source_id +expected_revision；要求approved；后台签名、核对后原子发布包与索引 |
| POST /releases/{id}/withdraw | 原因+expected_revision；索引revision递增，标记撤回；历史包保留审计 |
| GET /releases | 发布/撤回记录、来源、完整哈希、签名key_id、更新时间 |
| GET /sources、POST /sources | 管理源/允许域名/密钥与策略，单独能力检查；私有token写入密钥库 |

成功响应 `{data: ...}`；错误 `{error:{code,message,field,request_id}}`，401未登录、403无权限、409状态/身份冲突、413超限、422包无效、429限流。不得泄露主机路径、命令环境或密钥。中断上传暂不自动视为完整包；后续断点协议需另行版本化，不与NAS文件互传混用。

## 校验与发布要求

1. 所有包上传到隔离区域；首先核对**整个文件**长度/SHA256，再运行 Rust `spkg` 检查尾部、压缩段、manifest/归档、架构文件、签名。工具可以单独进程设置超时/内存限制，绝不执行包内脚本。
2. 提交者签名必须来自绑定开发者的已知key；未签名草稿允许显式开发预检，不能自动进入production发布。
3. 追加ELF/ABI、脚本审查、许可证、图片清洗、病毒与依赖漏洞检查；格式通过不等于安全。扫描不可用须有明确阻断/人工流程，不能显示“已安全扫描”。
4. 审核存储：提交者、审查者、每个阶段的工具版本、原包哈希、结果及发布签名。确认原包哈希与审查期间一致，防TOCTOU。
5. 内容寻址/不可变存储；发布路径与开发者原始文件名分离，禁止软链接/遍历。同一tuple新内容返回409，必须改套件版本。
6. 包上传完成并校验后才原子更新index.json与index.sig；客户端拿到任一一致revision即可验证，不留指向半包的索引。并发发布通过source revision锁串行化。
7. 重新封装官方签名时只替换签名区，压缩payload与已审核内容完全一致；保留开发者原包/签名与发布包各自完整哈希。变更后的最终SPKG重新校验，不混淆两种摘要。
8. 下载/安装统计只由可选、授权的汇总事件产生，不自动上传NAS身份或个人文件；失败原因脱敏。

## NAS后续消费接口（预定）

原生 `/api/v1/native/apps`、`/preview`、`/jobs` 和受限服务操作接口继续保留。新SPKG运行时建议独立 `/api/v1/packages` 命名空间，GET目录/已安装/来源要求native.read；上传、预览、确认安装/卸载/升级、来源写入及服务操作要求native.manage。新权限若更细分须显式迁移，不能默认扩展旧用户权限。

运行时必须提供上传/依赖/权限/端口/资源的真实预览、预览失效检测、签名信任说明、SSE日志与服务健康结果。具体OpenAPI在运行引擎实施时产出，当前不在主API注册占位路由或任意命令入口。
