#!/usr/bin/env python3 """Bounded code-review publication using the caller's authenticated adapter.""" from __future__ import annotations import hashlib import importlib.util import json import re from pathlib import Path # Reuse public JSON/page/cache and canonical spec codecs, not the spec-only publisher. _SPEC_PATH = (Path(__file__).resolve().parents[4] / 'spec/skills/gitea-implementation-spec-review/scripts/review_support.py') _spec = importlib.util.spec_from_file_location('gitea_native_spec_support', _SPEC_PATH) _support = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(_support) _LOCK_PATH = Path(__file__).resolve().parents[5] / 'lib/managed_lock.py' _lock_spec = importlib.util.spec_from_file_location('gitea_managed_lock', _LOCK_PATH) _locks = importlib.util.module_from_spec(_lock_spec) _lock_spec.loader.exec_module(_locks) _BROKER_PATH = Path(__file__).resolve().parents[5] / 'lib/managed_lock_broker.py' _broker_spec = importlib.util.spec_from_file_location('gitea_managed_lock_broker', _BROKER_PATH) _broker = importlib.util.module_from_spec(_broker_spec) _broker_spec.loader.exec_module(_broker) ValidationError = _support.ValidationError loads_json = _support.loads_json collect_pages = _support.collect_pages ORIGIN = 'https://gitea.jsfamily.quest' SCHEMA = 'gitea-agent.code-review-publication/v1' def fail(message): raise ValidationError(message) def require_adoption(declaration, revision): if declaration is None: fail('delegation adoption declaration required') try: repo_root = Path(__file__).resolve().parents[6] import sys if str(repo_root) not in sys.path: sys.path.insert(0, str(repo_root)) from harness.lib.delegation_adoption import AdoptionError, require_adoption as adopt except Exception: fail('delegation adoption unavailable') try: return adopt(declaration, expected_source={'kind': 'git_tree', 'revision': revision}, expected_stage='code-review') except AdoptionError as exc: fail(str(exc)) except Exception: fail('delegation adoption unavailable') def positive_id(value): if type(value) is not int or value < 1: fail('invalid positive identity') return value def digest(value, length): if type(value) is not str or not re.fullmatch('[0-9a-f]{' + str(length) + '}', value): fail('invalid digest') return value def marker(plan): t = plan['target'] return (f'') def validate_plan(plan): keys = {'schema', 'target', 'contract_sha256', 'reviewer', 'spec_reviewer', 'spec_review_id', 'spec_paths', 'verdict', 'body', 'provider_contract'} if type(plan) is not dict or set(plan) != keys or plan['schema'] != SCHEMA: fail('invalid publication plan') t = plan['target'] if type(t) is not dict or set(t) != {'owner', 'repository', 'issue', 'pull', 'head', 'base'}: fail('invalid target schema') for k in ['owner', 'repository']: value = t[k] if type(value) is not str or not re.fullmatch(r'[A-Za-z0-9_][A-Za-z0-9_.-]{0,254}', value): fail('invalid target identifier') for k in ['issue', 'pull']: positive_id(t[k]) for k in ['head', 'base']: digest(t[k], 40) digest(plan['contract_sha256'], 64) for k, login in [('reviewer', 'gitea-review-agent'), ('spec_reviewer', 'gitea-spec-agent')]: who = plan[k] if type(who) is not dict or set(who) != {'id', 'login'} or who['login'] != login: fail('invalid role identity') positive_id(who['id']) if plan['reviewer']['id'] == plan['spec_reviewer']['id']: fail('reviewer independence violation') positive_id(plan['spec_review_id']) paths = plan['spec_paths'] if type(paths) is not list or any(type(x) is not str or not x or x.startswith('/') or any(p in ['', '.', '..'] for p in x.split('/')) or any(ord(c) < 32 for c in x) for x in paths) or len(set(paths)) != len(paths): fail('invalid declared spec path scope') if type(plan['verdict']) is not str or plan['verdict'] not in ['approve', 'request_changes']: fail('unsupported publication verdict') body = plan['body'] if type(body) is not str or not 1 <= len(body) <= 250000: fail('invalid body') try: body.encode('utf-8') except UnicodeError: fail('invalid body encoding') if (not body.startswith(marker(plan) + '\n') or body.count('