fix(action): keep public schema within operation limit

This commit is contained in:
AIOS Owner Reconciliation
2026-08-25 22:02:17 +08:00
parent 767c7ff6a9
commit 4313f3e44a
3 changed files with 74 additions and 25 deletions
+1 -25
View File
@@ -1,7 +1,7 @@
openapi: 3.1.0
info:
title: AIOS GitOps Controlled Access API
version: V1R1C0-chatgpt-actions
version: V2R2C1-chatgpt-actions-30ops
description: Controlled ChatGPT Actions API for AIOS online GitOps baseline. Read endpoints are public. Write endpoints require Bearer token and create Git commits on non-main branches.
servers:
- url: https://cnnetmkt.top
@@ -483,18 +483,6 @@ paths:
schema: {$ref: '#/components/schemas/BranchRequest'}
responses: {'200': {description: Branch created}, '401': {description: Unauthorized}, '403': {description: Forbidden}}
x-openai-isConsequential: true
/api/file:
post:
operationId: commitFile
summary: Write a file and create a Git commit on a non-main branch
security: [{bearerAuth: []}]
requestBody:
required: true
content:
application/json:
schema: {$ref: '#/components/schemas/FileCommitRequest'}
responses: {'200': {description: File committed}, '400': {description: Secret rejected or invalid path}, '401': {description: Unauthorized}}
x-openai-isConsequential: true
/api/commit-file:
post:
operationId: commitFileAtomic
@@ -514,18 +502,6 @@ paths:
'413': {description: Request too large}
'503': {description: Push or remote verification unavailable; recoverable}
x-openai-isConsequential: true
/api/commit:
post:
operationId: commitChanges
summary: Commit existing workspace changes on a non-main branch
security: [{bearerAuth: []}]
requestBody:
required: false
content:
application/json:
schema: {$ref: '#/components/schemas/CommitRequest'}
responses: {'200': {description: Commit result}, '401': {description: Unauthorized}}
x-openai-isConsequential: true
/api/tag-publication-status:
get:
operationId: getTagPublicationStatus
@@ -0,0 +1,53 @@
# ChatGPT Action OpenAPI 操作数上限运行手册
## 目的
`https://cnnetmkt.top/api/openapi-chatgpt-actions.yaml` 必须保持不超过 ChatGPT
Action 导入支持的 30 个实际操作。OpenAPI 中同一路径的多个 HTTP method
分别计数;路径数量不等于操作数量。
## 单一来源与构建
规范唯一来源是 `docs/gitops/openapi-chatgpt-actions.yaml`。模型 API staging
构建脚本 `scripts/build_v2r2c1_model_api_staging.py` 将该文件复制到 immutable
artifact,并同时校验 `/v2/commit-files` runtime contract。禁止直接编辑已部署
artifact 或 production 文件。
变更后至少执行:
```bash
python3 - <<'PY'
import yaml
from pathlib import Path
doc = yaml.safe_load(Path('docs/gitops/openapi-chatgpt-actions.yaml').read_text())
methods = {'get', 'post', 'put', 'patch', 'delete', 'head', 'options'}
operations = [(p, m) for p, item in doc['paths'].items() for m in item if m in methods]
assert len(operations) <= 30, len(operations)
print(f'paths={len(doc["paths"])} operations={len(operations)}')
PY
PYTHONPATH=active-runtime/app python3 -m pytest -q tests/test_action_contract_regressions.py
```
## 公开面选择
公开 schema 保留受治理的 `/api/commit-file`、`/v2/commit-files` 以及 release、
tag publication、consistency、acceptance、saga 和 diff 操作。粗粒度旧别名
`/api/file` 与当前 isolated-writer policy 明确禁止的 `/api/commit` 不得重新加入
公开 Action schema;需要单文件 governed write 时使用 canonical writer,批量写入
使用 `/v2/commit-files`。
## 部署与复验
只使用 `scripts/build_v2r2c1_model_api_staging.py` 生成 staging artifact,保留
当前 systemd drop-in 备份,更新 staging model-api 的 artifact 路径后执行
`daemon-reload` 和 staging unit restart。部署后从公网重新抓取 schema,验证:
- HTTP 200,Content-Type 为 YAML;
- 实际操作数为 30 或更少;
- `commitFilesGoverned` 仍包含 required `files`,每项包含 `path`、`content_base64`;
- `/v2/runtime`、capabilities、release consistency/acceptance、tag status、
saga empty-state、diff small/empty/large smoke 均正常;
- staging unit active,production/main/tag/baseline 未写入。
Action 客户端可能缓存旧规范。公网 schema 复验通过后,在 ChatGPT Action 编辑器
重新导入该 URL 或执行刷新;服务端无法替代客户端已保存的旧 schema cache。
+20
View File
@@ -6,6 +6,7 @@ import sys
from pathlib import Path
import pytest
import yaml
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))
@@ -88,6 +89,25 @@ def test_published_action_v2_paths_are_bound_to_staging_bridge():
assert "Authorization $http_authorization" in route_script
def test_published_action_schema_stays_within_chatgpt_operation_limit():
schema = yaml.safe_load(
(ROOT / "docs/gitops/openapi-chatgpt-actions.yaml").read_text()
)
operations = [
(path, method, operation)
for path, item in schema["paths"].items()
for method, operation in item.items()
if method.lower() in {"get", "post", "put", "patch", "delete", "head", "options"}
]
assert len(operations) <= 30
assert len(operations) == 30
assert "commitFilesGoverned" in {
operation["operationId"] for _, _, operation in operations
}
assert "/api/file" not in schema["paths"]
assert "/api/commit" not in schema["paths"]
def test_commit_files_runtime_and_published_schema_have_same_required_fields():
runtime = operation_contracts()["commitFilesGoverned"]["required_fields"]
assert runtime == list(OPERATION_REQUIRED_FIELDS["commitFilesGoverned"])