feat(gitops): expose governed task continuation contract

This commit is contained in:
AIOS Governed Continuation
2026-08-24 21:15:07 +08:00
parent 2c8c98a11f
commit 341d276f18
2 changed files with 146 additions and 0 deletions
+34
View File
@@ -160,6 +160,23 @@ components:
properties:
text: {type: string}
branch: {type: string}
CreateGovernedTaskRequest:
type: object
additionalProperties: false
required: [task_id, repository, base_oid, target_branch, risk, description, idempotency_key]
properties:
task_id: {type: string, minLength: 1}
repository: {type: string, const: aios/aios}
base_oid: {type: string, pattern: '^[0-9a-f]{40}$'}
target_branch: {type: string, pattern: '^agent/[A-Za-z0-9][A-Za-z0-9._/-]{2,179}$'}
risk: {type: string, enum: [low, medium, high, engineering]}
description: {type: string, minLength: 1}
idempotency_key: {type: string, minLength: 1, maxLength: 256}
expected_branch_oid: {type: string, pattern: '^[0-9a-f]{40}$'}
generation: {type: integer, minimum: 1}
parent_task_id: {type: string, minLength: 1}
parent_job_id: {type: string, pattern: '^job-[A-Za-z0-9][A-Za-z0-9._-]{7,255}$'}
priority: {type: integer, minimum: -100, maximum: 100}
DeploymentPlan:
type: object
required: [service, release_path, release_root, cutover_link, dropin_path, dropin_sha256, systemd_unit_sha256, rollback_path, rollback_sha256, source_commit, tree_oid, artifact_sha256, manifest_sha256, package_closure_sha256, authoritative_git_dir, repository_identity, writer_expected, baseline_before_sha256, registry_before_sha256, production_tag_refset_before_sha256, health_contract_version, timeout_policy, retry_policy, policy_sha256, health_contract]
@@ -349,6 +366,23 @@ components:
operations: {type: array, items: {type: string}}
operation_contracts: {type: object, additionalProperties: true}
paths:
/createGovernedTask:
post:
operationId: createGovernedTask
summary: Create or idempotently return a governed task binding through the existing Bridge
security: [{bearerAuth: []}]
requestBody:
required: true
content:
application/json:
schema: {$ref: '#/components/schemas/CreateGovernedTaskRequest'}
responses:
'200': {description: Governed task binding created or returned idempotently}
'400': {description: Invalid governed task or continuation binding}
'401': {description: Caller authorization required}
'409': {description: Durable task, parent, branch, or generation conflict}
'503': {description: Governed Bridge or server-side control credential unavailable}
x-openai-isConsequential: true
/createReleaseIntent:
post:
operationId: createReleaseIntent
@@ -0,0 +1,112 @@
from pathlib import Path
import pytest
import yaml
from aios_chatgpt_bridge_v2 import OPERATION_REQUIRED_FIELDS
from aios_chatgpt_bridge_v2_server import BridgeHandler, _HTTPError, ROUTES
ROOT = Path(__file__).resolve().parents[1]
OPENAPI = ROOT / "docs" / "gitops" / "openapi-chatgpt-actions.yaml"
REQUIRED = {
"task_id",
"repository",
"base_oid",
"target_branch",
"risk",
"description",
"idempotency_key",
}
OPTIONAL_CONTINUATION = {
"expected_branch_oid",
"generation",
"parent_task_id",
"parent_job_id",
"priority",
}
def _document():
return yaml.safe_load(OPENAPI.read_text(encoding="utf-8"))
def _create_request():
return {
"task_id": "continuation-contract-test",
"repository": "aios/aios",
"base_oid": "a" * 40,
"target_branch": "agent/continuation-contract-test",
"risk": "engineering",
"description": "contract test",
"idempotency_key": "continuation-contract-test-v1",
}
def test_create_governed_task_openapi_contract_exposes_continuation_fields():
document = _document()
operation = document["paths"]["/createGovernedTask"]["post"]
schema_ref = operation["requestBody"]["content"]["application/json"]["schema"]
schema = document["components"]["schemas"][schema_ref["$ref"].rsplit("/", 1)[-1]]
assert operation["operationId"] == "createGovernedTask"
assert operation["security"] == [{"bearerAuth": []}]
assert operation["x-openai-isConsequential"] is True
assert set(schema["required"]) == REQUIRED
assert schema["additionalProperties"] is False
assert OPTIONAL_CONTINUATION <= set(schema["properties"])
assert not OPTIONAL_CONTINUATION.intersection(schema["required"])
assert schema["properties"]["repository"]["const"] == "aios/aios"
assert schema["properties"]["generation"]["minimum"] == 1
assert schema["properties"]["priority"] == {
"type": "integer",
"minimum": -100,
"maximum": 100,
}
def test_create_governed_task_route_and_required_fields_match_bridge():
assert ROUTES["/v2/governed-task"] == "createGovernedTask"
assert tuple(OPERATION_REQUIRED_FIELDS["createGovernedTask"]) == (
"task_id",
"repository",
"base_oid",
"target_branch",
"risk",
"description",
"idempotency_key",
)
def test_bridge_execution_plan_and_envelope_routes_remain_exposed():
assert ROUTES["/v2/execution-envelope"] == "projectOnlineAgentExecution"
assert ROUTES["/v2/execution-plan"] == "registerOnlineAgentExecutionPlan"
def test_bridge_allowlist_accepts_parent_pair_and_priority_but_rejects_unknown():
handler = BridgeHandler.__new__(BridgeHandler)
body = _create_request()
body.update(
{
"expected_branch_oid": "a" * 40,
"generation": 2,
"parent_task_id": "continuation-parent-test",
"parent_job_id": "job-continuation-parent-test",
"priority": 100,
}
)
handler._allowed("createGovernedTask", body)
invalid = dict(body)
invalid["unexpected_field"] = True
with pytest.raises(_HTTPError, match="UNKNOWN_FIELDS"):
handler._allowed("createGovernedTask", invalid)
def test_openapi_does_not_add_credential_fields_to_create_contract():
document = _document()
properties = set(
document["components"]["schemas"]["CreateGovernedTaskRequest"]["properties"]
)
forbidden = {"authorization", "bearer", "token", "credential", "secret", "password", "api_key"}
assert properties.isdisjoint(forbidden)