fix(integration): reconcile release loaders and internal contracts

Keep frozen-pin validation strict while recognizing the current verified-byte restore loader, and publish the existing private RC06 participant contract without opening public routes. Make isolated regression collection and two-process fixture diagnostics reliable without changing signer runtime behavior.
This commit is contained in:
2026-10-08 21:24:28 +08:00
parent da8ea680f9
commit dc6b739e22
7 changed files with 131 additions and 37 deletions
+1
View File
@@ -7,6 +7,7 @@ testpaths = [
]
pythonpath = [
"yuqei-contract-platform/services/contract-api/src",
"yuqei-contract-platform/services/contract-api/tests",
"yuqei-ai-platform/services/ai-platform-api/src",
"yuqei-ai-platform/services/worker/src",
"yuqei-ai-sdk-python/src",
@@ -1,5 +1,10 @@
components:
schemas:
PromptCapabilityRequest: {"properties":{"capability":{"type":"string","maxLength":128,"minLength":43,"title":"Capability"}},"additionalProperties":false,"type":"object","required":["capability"],"title":"PromptCapabilityRequest"}
PromptModuleInput: {"properties":{"category":{"type":"string","enum":["drafting","review"],"title":"Category"},"key":{"type":"string","maxLength":128,"minLength":1,"title":"Key"},"version":{"type":"string","maxLength":128,"minLength":1,"title":"Version"},"content":{"type":"string","maxLength":200000,"minLength":1,"title":"Content"},"content_sha256":{"type":"string","pattern":"^[a-f0-9]{64}$","title":"Content Sha256"},"publication_mapping":{"additionalProperties":{"type":"string"},"type":"object","title":"Publication Mapping"},"module_payload_sha256":{"type":"string","pattern":"^[a-f0-9]{64}$","title":"Module Payload Sha256"}},"additionalProperties":false,"type":"object","required":["category","key","version","content","content_sha256","publication_mapping","module_payload_sha256"],"title":"PromptModuleInput"}
PromptPrepareRequest: {"properties":{"transaction_id":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._:-]{7,63}$","title":"Transaction Id"},"idempotency_key":{"type":"string","maxLength":160,"minLength":8,"title":"Idempotency Key"},"candidate_commit":{"type":"string","pattern":"^(?:[a-f0-9]{40}|[a-f0-9]{64})$","title":"Candidate Commit"},"release_image_digest":{"type":"string","pattern":"^sha256:[a-f0-9]{64}$","title":"Release Image Digest"},"candidate_tag":{"type":"string","maxLength":128,"minLength":1,"title":"Candidate Tag"},"batch_manifest_raw_sha256":{"type":"string","pattern":"^[a-f0-9]{64}$","title":"Batch Manifest Raw Sha256"},"batch_manifest_payload_sha256":{"type":"string","pattern":"^[a-f0-9]{64}$","title":"Batch Manifest Payload Sha256"},"approval_receipt_sha256":{"type":"string","pattern":"^[a-f0-9]{64}$","title":"Approval Receipt Sha256"},"authority_expires_at":{"type":"string","format":"date-time","title":"Authority Expires At"},"compensation_capability_sha256":{"type":"string","pattern":"^[a-f0-9]{64}$","title":"Compensation Capability Sha256"},"modules":{"items":{"$ref":"#/components/schemas/PromptModuleInput"},"type":"array","title":"Modules"},"runtime_identities":{"items":{"$ref":"#/components/schemas/RuntimeIdentityInput"},"type":"array","title":"Runtime Identities"}},"additionalProperties":false,"type":"object","required":["transaction_id","idempotency_key","candidate_commit","release_image_digest","candidate_tag","batch_manifest_raw_sha256","batch_manifest_payload_sha256","approval_receipt_sha256","authority_expires_at","compensation_capability_sha256","modules","runtime_identities"],"title":"PromptPrepareRequest"}
PromptTransactionStatus: {"properties":{"transaction_id":{"type":"string","title":"Transaction Id"},"state":{"type":"string","title":"State"},"candidate_commit":{"type":"string","title":"Candidate Commit"},"release_image_digest":{"type":"string","title":"Release Image Digest"},"candidate_tag":{"type":"string","title":"Candidate Tag"},"batch_manifest_raw_sha256":{"type":"string","title":"Batch Manifest Raw Sha256"},"batch_manifest_payload_sha256":{"type":"string","title":"Batch Manifest Payload Sha256"},"approval_receipt_sha256":{"type":"string","title":"Approval Receipt Sha256"},"authority_expires_at":{"type":"string","format":"date-time","title":"Authority Expires At"},"item_results":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Item Results"},"runtime_snapshots":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Runtime Snapshots"},"write_count":{"type":"integer","title":"Write Count","default":0},"runtime_snapshot_count":{"type":"integer","title":"Runtime Snapshot Count","default":0},"no_go":{"type":"boolean","title":"No Go","default":false},"committed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Committed At"},"sealed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Sealed At"},"compensated_from_state":{"anyOf":[{"type":"string","enum":["prepared","committed"]},{"type":"null"}],"title":"Compensated From State"},"compensation_item_results":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Compensation Item Results"},"runtime_snapshot_compensation_results":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Runtime Snapshot Compensation Results"},"restored_item_count":{"type":"integer","title":"Restored Item Count","default":0},"removed_item_count":{"type":"integer","title":"Removed Item Count","default":0},"unchanged_item_count":{"type":"integer","title":"Unchanged Item Count","default":0},"compensated_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Compensated At"},"compensation_evidence_sha256":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Compensation Evidence Sha256"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"}},"type":"object","required":["transaction_id","state","candidate_commit","release_image_digest","candidate_tag","batch_manifest_raw_sha256","batch_manifest_payload_sha256","approval_receipt_sha256","authority_expires_at"],"title":"PromptTransactionStatus"}
RuntimeIdentityInput: {"properties":{"name":{"type":"string","maxLength":128,"minLength":1,"title":"Name"},"version":{"type":"string","maxLength":128,"minLength":1,"title":"Version"},"content_sha256":{"type":"string","pattern":"^[a-f0-9]{64}$","title":"Content Sha256"},"source_kind":{"type":"string","enum":["composed_drafting_modules","new_review_module_composite","existing_domain_prompt_asset"],"title":"Source Kind"}},"additionalProperties":false,"type":"object","required":["name","version","content_sha256","source_kind"],"title":"RuntimeIdentityInput"}
AiQualityAttribution:
properties:
by_knowledge_base:
@@ -6870,6 +6875,11 @@ info:
description: V2 AI platform contract for model routing, legal QA, legal review, knowledge bases, and AI audit.
openapi: 3.1.0
paths:
/api/v1/internal/rc06-publications/prepare: {"post":{"tags":["internal","rc06"],"summary":"Prepare","operationId":"prepare_api_v1_internal_rc06_publications_prepare_post","parameters":[{"name":"x-rc06-publication-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Rc06-Publication-Service-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromptPrepareRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromptTransactionStatus"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}
/api/v1/internal/rc06-publications/{transaction_id}/commit: {"post":{"tags":["internal","rc06"],"summary":"Commit","operationId":"commit_api_v1_internal_rc06_publications__transaction_id__commit_post","parameters":[{"name":"transaction_id","in":"path","required":true,"schema":{"type":"string","title":"Transaction Id"}},{"name":"x-rc06-publication-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Rc06-Publication-Service-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromptTransactionStatus"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}
/api/v1/internal/rc06-publications/{transaction_id}: {"get":{"tags":["internal","rc06"],"summary":"Status","operationId":"status_api_v1_internal_rc06_publications__transaction_id__get","parameters":[{"name":"transaction_id","in":"path","required":true,"schema":{"type":"string","title":"Transaction Id"}},{"name":"x-rc06-publication-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Rc06-Publication-Service-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromptTransactionStatus"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}
/api/v1/internal/rc06-publications/{transaction_id}/seal: {"post":{"tags":["internal","rc06"],"summary":"Seal","operationId":"seal_api_v1_internal_rc06_publications__transaction_id__seal_post","parameters":[{"name":"transaction_id","in":"path","required":true,"schema":{"type":"string","title":"Transaction Id"}},{"name":"x-rc06-publication-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Rc06-Publication-Service-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromptCapabilityRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromptTransactionStatus"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}
/api/v1/internal/rc06-publications/{transaction_id}/compensate: {"post":{"tags":["internal","rc06"],"summary":"Compensate","operationId":"compensate_api_v1_internal_rc06_publications__transaction_id__compensate_post","parameters":[{"name":"transaction_id","in":"path","required":true,"schema":{"type":"string","title":"Transaction Id"}},{"name":"x-rc06-publication-service-key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Rc06-Publication-Service-Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromptCapabilityRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromptTransactionStatus"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}
/api/v1/audit/ai-runs:
get:
operationId: list_ai_runs_api_v1_audit_ai_runs_get
@@ -3,6 +3,7 @@ from __future__ import annotations
import hashlib
import json
from datetime import UTC, datetime, timedelta
from pathlib import Path
import pytest
from fastapi.testclient import TestClient
@@ -32,7 +33,7 @@ from yuqei_ai_platform_api.rc06_publication import (
Rc06PublicationError,
_source_inventory,
)
from yuqei_ai_platform_api.repository import SqlAlchemyAiPlatformRepository
from yuqei_ai_platform_api.repository import InMemoryAiPlatformRepository, SqlAlchemyAiPlatformRepository
CANDIDATE_COMMIT = "a" * 40
@@ -95,6 +96,43 @@ def _request(transaction_id: str = "rc06-ai-transaction-0001") -> PromptPrepareR
)
def test_internal_rc06_openapi_fragment_matches_current_participant(tmp_path):
app = create_app(
AiPlatformSettings(
_env_file=None,
environment="test",
repository_backend="memory",
provider_call_mode="disabled",
object_storage_local_dir=str(tmp_path / "objects"),
),
repository=InMemoryAiPlatformRepository(),
)
runtime = app.openapi()
published = (
Path(__file__).resolve().parents[3] / "packages/ai-openapi/openapi.yaml"
).read_text(encoding="utf-8")
decoder = json.JSONDecoder()
paths = {
path: value for path, value in runtime["paths"].items()
if path.startswith("/api/v1/internal/rc06-publications")
}
assert len(paths) == 5
# The internal fragment uses JSON, which is valid YAML, without a test-only parser dependency.
for path, expected in paths.items():
marker = f" {path}: "
start = published.index(marker) + len(marker)
actual, _ = decoder.raw_decode(published[start:])
assert actual == expected
for name in (
"PromptCapabilityRequest", "PromptModuleInput", "PromptPrepareRequest",
"PromptTransactionStatus", "RuntimeIdentityInput",
):
marker = f" {name}: "
start = published.index(marker) + len(marker)
actual, _ = decoder.raw_decode(published[start:])
assert actual == runtime["components"]["schemas"][name]
def test_prepare_rejects_expired_authority_without_journal_or_prompt_writes(tmp_path):
repository = _repository(tmp_path)
try:
@@ -2516,16 +2516,42 @@ def _exec_verified_module(name: str, path: Path, raw: bytes) -> Any:
"""
_VERIFIED_SNAPSHOT_MODULE_EXEC_TEMPLATE = """
def _exec_verified_module(raw: bytes, path: Path, module_name: str) -> Any:
try:
code = compile(raw, os.fspath(path), "exec", dont_inherit=True)
except (SyntaxError, UnicodeError, ValueError) as exc:
raise SnapshotRestorePlanError("verified validator source cannot be compiled") from exc
module = types.ModuleType(module_name)
module.__file__ = os.fspath(path)
module.__package__ = ""
module.__loader__ = None
module.__spec__ = importlib.util.spec_from_loader(
module_name, loader=None, origin=os.fspath(path)
)
sys.modules[module_name] = module
try:
exec(code, module.__dict__)
except Exception as exc:
sys.modules.pop(module_name, None)
raise SnapshotRestorePlanError("verified validator source failed to load") from exc
return module
"""
def _safe_verified_module_exec(call: ast.Call, parents: Mapping[ast.AST, ast.AST]) -> bool:
parent: ast.AST | None = call
while parent is not None and not isinstance(parent, (ast.FunctionDef, ast.AsyncFunctionDef)):
parent = parents.get(parent)
if not isinstance(parent, ast.FunctionDef):
return False
expected = ast.parse(_VERIFIED_MODULE_EXEC_TEMPLATE).body[0]
return ast.dump(parent, include_attributes=False) == ast.dump(
expected,
include_attributes=False,
observed = ast.dump(parent, include_attributes=False)
return any(
observed == ast.dump(ast.parse(template).body[0], include_attributes=False)
for template in (
_VERIFIED_MODULE_EXEC_TEMPLATE,
_VERIFIED_SNAPSHOT_MODULE_EXEC_TEMPLATE,
)
)
@@ -8,8 +8,6 @@ from pathlib import Path
import pytest
import multiscene_eval_plan
ROOT = Path(__file__).resolve().parents[2]
RUNNER_PATH = ROOT / "yuqei-infra/scripts/run-core-drafting-smoke.py"
@@ -18,6 +16,8 @@ assert SPEC and SPEC.loader
RUNNER = importlib.util.module_from_spec(SPEC)
SPEC.loader.exec_module(RUNNER)
import multiscene_eval_plan
@pytest.mark.parametrize(
("raw", "matches"),
@@ -2876,13 +2876,16 @@ def test_two_process_legacy_adoption_never_deletes_the_other_process_marker(
state_directory, key_directory = _make_legacy_default_state(tmp_path, monkeypatch)
ready = tmp_path / "holder-ready"
release = tmp_path / "holder-release"
# Windows validates owner ACLs in child processes before reaching the barrier.
timeout_seconds = 120 if os.name == "nt" else 20
child = r'''
import importlib.util
import pathlib
import sys
import time
script, state_raw, ready_raw, release_raw, mode = sys.argv[1:]
script, state_raw, ready_raw, release_raw, timeout_raw, mode = sys.argv[1:]
timeout_seconds = float(timeout_raw)
spec = importlib.util.spec_from_file_location("signer_concurrency_fixture", script)
module = importlib.util.module_from_spec(spec)
assert spec is not None and spec.loader is not None
@@ -2898,7 +2901,7 @@ if mode == "holder":
original(directory, **kwargs)
if directory == state / "keys" and not ready.exists():
ready.write_text("ready", encoding="utf-8")
deadline = time.monotonic() + 20
deadline = time.monotonic() + timeout_seconds
while not release.exists() and time.monotonic() < deadline:
time.sleep(0.05)
if not release.exists():
@@ -2923,30 +2926,37 @@ print("ACQUIRED")
os.fspath(state_directory),
os.fspath(ready),
os.fspath(release),
str(timeout_seconds),
]
holder = subprocess.Popen(
[*command, "holder"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
)
try:
deadline = time.monotonic() + 20
while not ready.exists() and time.monotonic() < deadline and holder.poll() is None:
time.sleep(0.05)
assert ready.is_file(), holder.communicate(timeout=5)
contender = subprocess.run(
[*command, "contender"],
check=False,
capture_output=True,
text=True,
timeout=30,
)
assert contender.returncode == 0, contender.stderr or contender.stdout
assert "BUSY" in contender.stdout
finally:
release.write_text("release", encoding="utf-8")
holder_stdout, holder_stderr = holder.communicate(timeout=30)
stdout_path = tmp_path / "holder.stdout"
stderr_path = tmp_path / "holder.stderr"
with stdout_path.open("w", encoding="utf-8") as stdout, stderr_path.open(
"w", encoding="utf-8"
) as stderr:
holder = subprocess.Popen([*command, "holder"], stdout=stdout, stderr=stderr)
try:
deadline = time.monotonic() + timeout_seconds
while not ready.exists() and time.monotonic() < deadline and holder.poll() is None:
time.sleep(0.05)
assert ready.is_file(), (
stderr_path.read_text(encoding="utf-8")
or stdout_path.read_text(encoding="utf-8")
or "holder did not reach the owner-marker barrier"
)
contender = subprocess.run(
[*command, "contender"],
check=False,
capture_output=True,
text=True,
timeout=timeout_seconds,
)
assert contender.returncode == 0, contender.stderr or contender.stdout
assert "BUSY" in contender.stdout
finally:
release.write_text("release", encoding="utf-8")
holder.wait(timeout=timeout_seconds)
holder_stdout = stdout_path.read_text(encoding="utf-8")
holder_stderr = stderr_path.read_text(encoding="utf-8")
assert holder.returncode == 0, holder_stderr or holder_stdout
assert "ACQUIRED" in holder_stdout
assert (key_directory / signer.OWNER_MARKER_FILENAME).is_file()
@@ -1121,13 +1121,22 @@ def test_pin_planner_isolated_runtime_detects_import_side_effect_override(
)
@pytest.mark.parametrize(
("filename", "module_name"),
(
("plan-rollback-rehearsal.py", "name"),
("plan-first-release-snapshot-restore.py", "module_name"),
),
)
def test_pin_planner_rejects_modified_verified_module_exec_loader(
tmp_path: Path,
filename: str,
module_name: str,
) -> None:
state, repo, _plan = _pin_plan_fixture(tmp_path, include_online=False)
rollback = repo / "yuqei-infra/deploy/plan-rollback-rehearsal.py"
original = rollback.read_text(encoding="utf-8")
needle = ' module = types.ModuleType(name)\n'
planner = repo / "yuqei-infra/deploy" / filename
original = planner.read_text(encoding="utf-8")
needle = f' module = types.ModuleType({module_name})\n'
replacement = (
" if sys.argv[0] != '-c':\n"
" module = sys.modules[__name__]\n"
@@ -1135,10 +1144,10 @@ def test_pin_planner_rejects_modified_verified_module_exec_loader(
+ "f" * 64
+ "'\"\n"
" else:\n"
" module = types.ModuleType(name)\n"
f" module = types.ModuleType({module_name})\n"
)
assert needle in original
rollback.write_text(original.replace(needle, replacement, 1), encoding="utf-8")
planner.write_text(original.replace(needle, replacement, 1), encoding="utf-8")
with pytest.raises(authority.AuthorityError, match="untrusted dynamic exec"):
authority.plan_pin_updates(