212 lines
7.6 KiB
Python
212 lines
7.6 KiB
Python
import base64
|
|
from pathlib import Path
|
|
|
|
from aios_authority_git_executor import AuthorityGitExecutor
|
|
from aios_chatgpt_bridge_v2 import BridgeV2Adapter, OPERATION_REQUIRED_FIELDS
|
|
from aios_chatgpt_bridge_v2_server import BridgeHandler, RuntimeConfig
|
|
from aios_continuation_executor import GiteaContinuationRemote, ServerSideCredentialProjection
|
|
from aios_continuation_lease import WriterLeaseRequestV2
|
|
|
|
|
|
class Probe:
|
|
def __init__(self, present=False):
|
|
self.present = present
|
|
|
|
def branch_exists(self, _branch):
|
|
return self.present
|
|
|
|
def branch_head(self, _branch):
|
|
return "a" * 40
|
|
|
|
def is_ancestor(self, _older, _newer):
|
|
return True
|
|
|
|
def commit_exists(self, _oid):
|
|
return True
|
|
|
|
|
|
def test_create_new_lease_is_exact_base_and_absent():
|
|
request = WriterLeaseRequestV2(
|
|
job_id="job-bridge-runtime-lineage-test",
|
|
task_id="TASK-P0-BRIDGE-V21-DURABLE-RECONCILIATION-20260809",
|
|
repository="aios/aios",
|
|
branch_mode="CREATE_NEW",
|
|
base_oid="a" * 40,
|
|
expected_branch_oid="a" * 40,
|
|
target_branch="agent/p0-bridge-v21-durable-reconciliation-20260809",
|
|
generation=1,
|
|
)
|
|
request.validate(Probe())
|
|
|
|
|
|
def test_create_new_lease_rejects_existing_target():
|
|
request = WriterLeaseRequestV2(
|
|
job_id="job-bridge-runtime-lineage-test",
|
|
task_id="task",
|
|
repository="aios/aios",
|
|
branch_mode="CREATE_NEW",
|
|
base_oid="a" * 40,
|
|
expected_branch_oid="a" * 40,
|
|
target_branch="agent/existing-target",
|
|
generation=1,
|
|
)
|
|
try:
|
|
request.validate(Probe(True))
|
|
except Exception as exc:
|
|
assert str(exc) == "TARGET_BRANCH_ALREADY_EXISTS"
|
|
else:
|
|
raise AssertionError("existing CREATE_NEW target must fail")
|
|
|
|
|
|
def test_slash_branch_uses_paginated_collection():
|
|
credential = ServerSideCredentialProjection(Path("/tmp/key"), Path("/tmp/token"), active=True)
|
|
calls = []
|
|
|
|
class FakeRemote(GiteaContinuationRemote):
|
|
def _api(self, path):
|
|
calls.append(path)
|
|
if "page=1" in path:
|
|
return [{"name": f"agent/other-{i}", "commit": {"id": "b" * 40}} for i in range(50)]
|
|
return [{"name": "agent/slash/branch", "commit": {"id": "c" * 40}}]
|
|
|
|
remote = FakeRemote(Path("/tmp"), credential)
|
|
assert remote.read_api_branch("agent/slash/branch") == "c" * 40
|
|
assert calls[0].endswith("branches?page=1&limit=50")
|
|
assert calls[1].endswith("branches?page=2&limit=50")
|
|
|
|
|
|
def test_http_route_contract_is_complete():
|
|
expected = {
|
|
"/v2/runtime", "/v2/capabilities", "/v2/governed-task",
|
|
"/v2/writer-lease", "/v2/writer-lease/bootstrap", "/v2/writer-lease/renew", "/v2/commit-file", "/v2/commit-files",
|
|
"/v2/job", "/v2/job/resume", "/v2/job/reconcile",
|
|
"/v2/tag/approval-request",
|
|
"/v2/tag/publish",
|
|
"/v2/tag/status",
|
|
"/v2/release/artifact",
|
|
"/v2/release/execute",
|
|
"/v2/release/consistency",
|
|
"/v2/release/acceptance",
|
|
}
|
|
from aios_chatgpt_bridge_v2_server import ROUTES
|
|
|
|
assert set(ROUTES) == expected
|
|
|
|
|
|
def test_renew_writer_lease_is_exposed_in_action_and_capability_contracts():
|
|
adapter = BridgeV2Adapter(runtime_status={})
|
|
capabilities = adapter.getGovernedWriteCapabilities()
|
|
contract = capabilities["operation_contracts"]["renewWriterLease"]
|
|
|
|
assert contract["method"] == "POST"
|
|
assert contract["path"] == "/v2/writer-lease/renew"
|
|
assert tuple(contract["required_fields"]) == OPERATION_REQUIRED_FIELDS["renewWriterLease"]
|
|
assert "runtime_rehydrated" in contract["response_fields"]
|
|
|
|
action_schema = Path("docs/gitops/openapi-chatgpt-actions.yaml").read_text(encoding="utf-8")
|
|
assert "/v2/writer-lease/renew:" in action_schema
|
|
assert "operationId: renewWriterLease" in action_schema
|
|
assert "BridgeWriterLeaseRecoveryRequest" in action_schema
|
|
assert "BridgeWriterLeaseRecoveryResponse" in action_schema
|
|
assert {
|
|
capabilities["operation_contracts"][operation]["path"]
|
|
for operation in (
|
|
"acquireWriterLease",
|
|
"renewWriterLease",
|
|
"commitFileGoverned",
|
|
"commitFilesGoverned",
|
|
)
|
|
} == {
|
|
"/v2/writer-lease",
|
|
"/v2/writer-lease/renew",
|
|
"/v2/commit-file",
|
|
"/v2/commit-files",
|
|
}
|
|
|
|
|
|
def test_bootstrap_writer_lease_is_exposed_in_action_and_capability_contracts():
|
|
adapter = BridgeV2Adapter(runtime_status={})
|
|
capabilities = adapter.getGovernedWriteCapabilities()
|
|
contract = capabilities["operation_contracts"]["bootstrapWriterLease"]
|
|
|
|
assert contract["method"] == "POST"
|
|
assert contract["path"] == "/v2/writer-lease/bootstrap"
|
|
assert tuple(contract["required_fields"]) == OPERATION_REQUIRED_FIELDS["bootstrapWriterLease"]
|
|
assert "bootstrapped" in contract["response_fields"]
|
|
assert "durable_branch_lease_present" in contract["response_fields"]
|
|
|
|
action_schema = Path("docs/gitops/openapi-chatgpt-actions.yaml").read_text(encoding="utf-8")
|
|
assert "/v2/writer-lease/bootstrap:" in action_schema
|
|
assert "operationId: bootstrapWriterLease" in action_schema
|
|
assert "bootstrapped: {type: boolean}" in action_schema
|
|
assert "durable_branch_lease_present: {type: boolean}" in action_schema
|
|
|
|
|
|
|
|
def test_http_allows_explicit_job_id_on_lease_and_commit_requests():
|
|
handler = BridgeHandler.__new__(BridgeHandler)
|
|
lease_body = {
|
|
"schema": WriterLeaseRequestV2.schema,
|
|
"task_id": "task",
|
|
"job_id": "job-explicit-runtime-lineage",
|
|
"repository": "aios/aios",
|
|
"branch_mode": "CONTINUE_EXISTING",
|
|
"base_oid": "a" * 40,
|
|
"expected_branch_oid": "a" * 40,
|
|
"target_branch": "agent/explicit-runtime-lineage",
|
|
"generation": 2,
|
|
"lease_seconds": 120,
|
|
}
|
|
handler._allowed("acquireWriterLease", lease_body)
|
|
handler._allowed(
|
|
"commitFilesGoverned",
|
|
{
|
|
"task_id": "task",
|
|
"job_id": "job-explicit-runtime-lineage",
|
|
"repository": "aios/aios",
|
|
"expected_branch_oid": "a" * 40,
|
|
"target_branch": "agent/explicit-runtime-lineage",
|
|
"generation": 2,
|
|
"idempotency_key": "commit-explicit-runtime-lineage",
|
|
"files": {"docs/x.txt": "eA=="},
|
|
"message": "test",
|
|
},
|
|
)
|
|
|
|
|
|
def test_http_allows_omitted_job_id_for_durable_server_resolution():
|
|
handler = BridgeHandler.__new__(BridgeHandler)
|
|
lease_body = {
|
|
"schema": WriterLeaseRequestV2.schema,
|
|
"task_id": "task",
|
|
"repository": "aios/aios",
|
|
"branch_mode": "CONTINUE_EXISTING",
|
|
"base_oid": "a" * 40,
|
|
"expected_branch_oid": "a" * 40,
|
|
"target_branch": "agent/implicit-runtime-lineage",
|
|
"generation": 2,
|
|
"lease_seconds": 120,
|
|
}
|
|
handler._allowed("acquireWriterLease", lease_body)
|
|
handler._allowed(
|
|
"commitFilesGoverned",
|
|
{
|
|
"task_id": "task",
|
|
"repository": "aios/aios",
|
|
"expected_branch_oid": "a" * 40,
|
|
"target_branch": "agent/implicit-runtime-lineage",
|
|
"generation": 2,
|
|
"idempotency_key": "commit-implicit-runtime-lineage",
|
|
"files": {"docs/x.txt": "eA=="},
|
|
"message": "test",
|
|
},
|
|
)
|
|
|
|
|
|
def test_capability_contracts_return_exact_job_id_lineage():
|
|
contracts = BridgeV2Adapter(runtime_status={}).getGovernedWriteCapabilities()["operation_contracts"]
|
|
for operation in ("acquireWriterLease", "bootstrapWriterLease", "renewWriterLease"):
|
|
assert "job_id" in contracts[operation]["response_fields"]
|
|
for operation in ("commitFileGoverned", "commitFilesGoverned"):
|
|
assert "job_id" in contracts[operation]["response_fields"]
|