fix(action): keep public schema within operation limit
This commit is contained in:
@@ -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。
|
||||
@@ -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"])
|
||||
|
||||
Reference in New Issue
Block a user