autonomy-smoke-tests Exact governed tree; evidence 7dbba7ff168e72af
autonomy-unit-tests Exact governed tree; evidence 7dbba7ff168e72af
campaign-approval-gate Exact governed tree; evidence 7dbba7ff168e72af
git-diff-check Exact governed tree; evidence 7dbba7ff168e72af
py-compile Exact governed tree; evidence 7dbba7ff168e72af
reconciliation-contract Exact governed tree; evidence 7dbba7ff168e72af
release-state-machine Exact governed tree; evidence 7dbba7ff168e72af
secret-scan Exact governed tree; evidence 7029b3eafb209066
signer-validator-contract Exact governed tree; evidence 7dbba7ff168e72af
631 lines
34 KiB
Python
631 lines
34 KiB
Python
"""Append-only C5 completion renewal boundary; activation requires registration.
|
|
|
|
The exact Owner-registered API, signer and completion host must call this
|
|
boundary. This module does not grant authority or perform deployment effects.
|
|
"""
|
|
import base64
|
|
import hashlib
|
|
import json
|
|
import math
|
|
import os
|
|
import stat
|
|
import time
|
|
from datetime import datetime, timezone
|
|
from pathlib import Path
|
|
|
|
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
|
|
from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
|
|
|
|
CID = 'rc-v2r2c5-5f65e458957d'
|
|
# Immutable release content remains compiled into the validator. Renewable
|
|
# authority identities and filesystem locations are installed only from the
|
|
# digest-bound, root-owned registration file (see configure_registered_bindings).
|
|
OLD_FP = '0' * 64
|
|
SOURCE = '5f65e458957dd51c9973cfa956a624f3cbf54990'
|
|
TREE = 'ddd239d43d63a7fbd3cff46119c71466c9443737'
|
|
ARTIFACT = '7f9d8409f07a5e0d36f5db7c55eb82ea70935fa731e057998f29cd1a5ca0a9ad'
|
|
PLAN = '370521afcf9b2288f6ad3803ca3554a46ee05d2042d53b19b4f4cb80e37a9684'
|
|
MUTABLE = {'issued_at', 'not_before', 'expires_at', 'nonce', 'fingerprint', 'signature'}
|
|
CAPABILITIES = ['baseline_registry_finalize', 'runtime_switch', 'tag_publish']
|
|
AUTHORITY_ROOT = Path('/unconfigured/c5-completion-authority')
|
|
STATE_ROOT = Path('/unconfigured/c5-completion-state')
|
|
OWNER_KEY = 'UNCONFIGURED'
|
|
TAG_OID = '6d1745ff496103db7e721a2b2bc624fda52c5dc8'
|
|
SAGA_HEAD = '0' * 64
|
|
HISTORICAL_ROOT = Path('/unconfigured/c5-completion-history')
|
|
CONTROLLER_WORKSPACE = Path('/unconfigured/c5-controller-workspace')
|
|
AUTHORITATIVE_GIT_DIR = Path('/unconfigured/c5-authoritative-git')
|
|
RUNTIME_REGISTRY_ROOT = Path('/unconfigured/c5-runtime-registry')
|
|
RUNTIME_BASELINE_PATH = Path('/unconfigured/c5-runtime-baseline.json')
|
|
TRUSTED_RELEASE_POLICY_PATH = Path('/unconfigured/c5-trusted-release-policy.json')
|
|
TRUSTED_RELEASE_POLICY_SHA256 = '0' * 64
|
|
BINDINGS_PATH_ENV = 'AIOS_C5_COMPLETION_BINDINGS_PATH'
|
|
BINDINGS_SHA256_ENV = 'AIOS_C5_COMPLETION_BINDINGS_SHA256'
|
|
_BINDINGS_DIGEST = None
|
|
RENEWAL_SOURCE_FILES = ('c5_completion_renewal.py', 'c5_release_execution_host.py',
|
|
'silent_release_hardening.py', 'c5_completion_signer.py',
|
|
'c5_completion_api.py', 'c5_completion_phase.py') # gitleaks:allow -- filenames only
|
|
PHASE_DEPENDENCIES = ('governed_tag_adapter.py', 'release_metadata_adapter.py',
|
|
'production_verification_phase_r1.py', 'public_business_acceptance_probe_r1.py',
|
|
'publisher-askpass.py', 'c5_staging_installation.py',
|
|
'aios_single_host_authority.py', 'registered_owner_signer_adapter.py')
|
|
|
|
|
|
class RenewalRejected(ValueError):
|
|
pass
|
|
|
|
|
|
def canonical(value):
|
|
return json.dumps(value, sort_keys=True, separators=(',', ':'), allow_nan=False).encode()
|
|
|
|
|
|
def digest(raw):
|
|
return hashlib.sha256(raw).hexdigest()
|
|
|
|
|
|
def validate_completion_lineage(gate):
|
|
"""Bind a current completion-only journal suffix to the frozen Saga15 head.
|
|
|
|
The suffix is authenticated by the enclosing registered Owner contract;
|
|
these checks preserve its origin and exclude deployment/source transitions.
|
|
"""
|
|
revision = gate.get('saga_revision')
|
|
suffix = gate.get('completion_journal_suffix', [])
|
|
observed = gate.get('observed_at')
|
|
if (type(revision) is not int or revision < 15 or not isinstance(suffix, list)
|
|
or type(observed) not in {int, float} or not math.isfinite(observed)):
|
|
raise RenewalRejected('COMPLETION_LINEAGE_INVALID')
|
|
if revision == 15:
|
|
if gate.get('saga_head') != SAGA_HEAD or suffix:
|
|
raise RenewalRejected('COMPLETION_LINEAGE_INVALID')
|
|
return
|
|
if not 0 < len(suffix) <= 64 or len(suffix) != revision - 15:
|
|
raise RenewalRejected('COMPLETION_LINEAGE_INVALID')
|
|
allowed = {
|
|
'owner_registered_completion_successor_tag_reconciliation': ('TAG_PENDING', {'RECONCILIATION_REQUIRED'}),
|
|
'owner_registered_tag_capability_successor_verified': ('TAG_VERIFIED', {'RECONCILIATION_REQUIRED', 'TAG_PENDING'}),
|
|
'baseline_registry_finalization_pending': ('BASELINE_REGISTRY_PENDING', {'TAG_VERIFIED'}),
|
|
'owner_registered_completion_successor_metadata_reconciliation': ('BASELINE_REGISTRY_PENDING', {'RECONCILIATION_REQUIRED'}),
|
|
'release_reconciliation_required': ('RECONCILIATION_REQUIRED', {'TAG_PENDING', 'TAG_VERIFIED', 'BASELINE_REGISTRY_PENDING'}),
|
|
}
|
|
previous, state = SAGA_HEAD, 'RECONCILIATION_REQUIRED'
|
|
for offset, event in enumerate(suffix, 16):
|
|
if (not isinstance(event, dict)
|
|
or set(event) != {'schema_version', 'sequence', 'previous_hash', 'payload', 'event_hash'}
|
|
or type(event['schema_version']) is not int or event['schema_version'] != 1
|
|
or type(event['sequence']) is not int or event['sequence'] != offset + 1
|
|
or event['previous_hash'] != previous):
|
|
raise RenewalRejected('COMPLETION_LINEAGE_INVALID')
|
|
payload = event['payload']
|
|
if (not isinstance(payload, dict)
|
|
or set(payload) != {'candidate_id', 'release_plan_id', 'revision', 'state', 'event', 'timestamp', 'details'}
|
|
or payload['candidate_id'] != CID
|
|
or payload['release_plan_id'] != 'pending-' + CID
|
|
or type(payload['revision']) is not int or payload['revision'] != offset
|
|
or not isinstance(payload['details'], dict)
|
|
or not isinstance(payload['event'], str) or payload['event'] not in allowed):
|
|
raise RenewalRejected('COMPLETION_LINEAGE_INVALID')
|
|
target, origins = allowed[payload['event']]
|
|
if payload['state'] != target or state not in origins:
|
|
raise RenewalRejected('COMPLETION_LINEAGE_INVALID')
|
|
if ('release_plan_sha256' in payload['details']
|
|
and payload['details']['release_plan_sha256'] != PLAN):
|
|
raise RenewalRejected('COMPLETION_LINEAGE_INVALID')
|
|
try:
|
|
if timestamp(payload['timestamp']) > gate['observed_at']:
|
|
raise RenewalRejected('COMPLETION_LINEAGE_INVALID')
|
|
actual = digest(canonical({key: event[key] for key in ('sequence', 'previous_hash', 'payload')}))
|
|
except (TypeError, ValueError, AttributeError, KeyError) as exc:
|
|
raise RenewalRejected('COMPLETION_LINEAGE_INVALID') from exc
|
|
if event['event_hash'] != actual:
|
|
raise RenewalRejected('COMPLETION_LINEAGE_INVALID')
|
|
previous, state = actual, target
|
|
if gate.get('saga_head') != previous:
|
|
raise RenewalRejected('COMPLETION_LINEAGE_INVALID')
|
|
|
|
|
|
def timestamp(value):
|
|
parsed = datetime.fromisoformat(value.replace('Z', '+00:00'))
|
|
if parsed.tzinfo is None or parsed.utcoffset().total_seconds() != 0:
|
|
raise RenewalRejected('UTC_REQUIRED')
|
|
return parsed.timestamp()
|
|
|
|
|
|
def verify_signature(approval, public_key):
|
|
payload = {k: v for k, v in approval.items() if k not in {'signature', 'fingerprint'}}
|
|
raw = canonical(payload)
|
|
if approval.get('fingerprint') != digest(raw):
|
|
raise RenewalRejected('APPROVAL_DIGEST_INVALID')
|
|
Ed25519PublicKey.from_public_bytes(public_key).verify(
|
|
base64.b64decode(approval['signature'], validate=True), raw
|
|
)
|
|
|
|
|
|
def validate_successor(old, new, public_key, *, now):
|
|
"""Validate historical predecessor and fresh identical-binding successor.
|
|
|
|
Historical signature verification does not authorize an expired effect.
|
|
The caller must separately verify its fresh registered Owner capability.
|
|
"""
|
|
verify_signature(old, public_key)
|
|
verify_signature(new, public_key)
|
|
exact = {'candidate_id': CID, 'source_commit': SOURCE, 'tree_oid': TREE,
|
|
'artifact_sha256': ARTIFACT, 'release_plan_sha256': PLAN,
|
|
'fingerprint': OLD_FP, 'capabilities': CAPABILITIES}
|
|
if any(old.get(k) != v for k, v in exact.items()):
|
|
raise RenewalRejected('EXACT_PREDECESSOR_REQUIRED')
|
|
if set(old) != set(new) or any(new[k] != old[k] for k in set(old) - MUTABLE):
|
|
raise RenewalRejected('IMMUTABLE_APPROVAL_BINDING_DRIFT')
|
|
if timestamp(old['expires_at']) > now:
|
|
raise RenewalRejected('PREDECESSOR_NOT_EXPIRED')
|
|
issued, not_before, expires = (timestamp(new[k]) for k in ['issued_at', 'not_before', 'expires_at'])
|
|
if not issued <= not_before <= now < expires or not 0 < expires - issued <= 900:
|
|
raise RenewalRejected('FRESH_BOUNDED_APPROVAL_REQUIRED')
|
|
if new['nonce'] == old['nonce'] or new['fingerprint'] == old['fingerprint']:
|
|
raise RenewalRejected('FRESH_APPROVAL_IDENTITY_REQUIRED')
|
|
return new['fingerprint']
|
|
|
|
|
|
def secure_bytes(path, owner_uid=0):
|
|
path = Path(path)
|
|
descriptor = os.open(path, os.O_RDONLY | os.O_NOFOLLOW)
|
|
with os.fdopen(descriptor, 'rb') as stream:
|
|
metadata = os.fstat(stream.fileno())
|
|
if not stat.S_ISREG(metadata.st_mode) or metadata.st_uid != owner_uid or metadata.st_mode & 0o022:
|
|
raise RenewalRejected('UNSAFE_RENEWAL_FILE')
|
|
return stream.read()
|
|
|
|
|
|
def _safe_parents(path):
|
|
"""Reject writable or symlinked ancestors before opening authority files."""
|
|
path = Path(path)
|
|
if not path.is_absolute() or '..' in path.parts:
|
|
raise RenewalRejected('ABSOLUTE_CANONICAL_PATH_REQUIRED')
|
|
for parent in path.parents:
|
|
info = parent.lstat()
|
|
if not stat.S_ISDIR(info.st_mode) or info.st_uid != 0 or info.st_mode & 0o022:
|
|
raise RenewalRejected('UNSAFE_AUTHORITY_ANCESTOR')
|
|
|
|
|
|
def _sha(value):
|
|
return isinstance(value, str) and len(value) == 64 and all(c in '0123456789abcdef' for c in value)
|
|
|
|
|
|
def _oid(value):
|
|
return isinstance(value, str) and len(value) == 40 and all(c in '0123456789abcdef' for c in value)
|
|
|
|
|
|
def configure_registered_bindings(path=None, expected_sha256=None, *, owner_uid=0):
|
|
"""Install renewable completion bindings from one authenticated file.
|
|
|
|
No historical approval fingerprint, Saga head, Owner key, or authority/state
|
|
path is a runtime default. The service registration must provide both the
|
|
absolute file path and its SHA-256 digest.
|
|
"""
|
|
global _BINDINGS_DIGEST
|
|
path = Path(path or os.environ.get(BINDINGS_PATH_ENV, ''))
|
|
expected_sha256 = expected_sha256 or os.environ.get(BINDINGS_SHA256_ENV, '')
|
|
if not path.is_absolute() or not _sha(expected_sha256):
|
|
raise RenewalRejected('REGISTERED_COMPLETION_BINDINGS_REQUIRED')
|
|
_safe_parents(path)
|
|
raw = secure_bytes(path, owner_uid=owner_uid)
|
|
if digest(raw) != expected_sha256:
|
|
raise RenewalRejected('COMPLETION_BINDINGS_DIGEST_MISMATCH')
|
|
if _BINDINGS_DIGEST is not None and _BINDINGS_DIGEST != expected_sha256:
|
|
raise RenewalRejected('COMPLETION_BINDINGS_REBIND_FORBIDDEN')
|
|
try:
|
|
value = json.loads(raw)
|
|
except (UnicodeDecodeError, json.JSONDecodeError) as exc:
|
|
raise RenewalRejected('COMPLETION_BINDINGS_INVALID') from exc
|
|
fields = {
|
|
'schema', 'authority_root', 'state_root', 'owner_key_id',
|
|
'predecessor_fingerprint', 'saga_head', 'historical_root',
|
|
'controller_workspace', 'authoritative_git_dir',
|
|
'runtime_registry_root', 'runtime_baseline_path',
|
|
'trusted_release_policy_path', 'trusted_release_policy_sha256',
|
|
}
|
|
if not isinstance(value, dict) or set(value) != fields or value.get('schema') != 'aios.c5.completion-bindings.v1':
|
|
raise RenewalRejected('COMPLETION_BINDINGS_SCHEMA_INVALID')
|
|
authority_root = Path(value['authority_root'])
|
|
state_root = Path(value['state_root'])
|
|
governed_paths = {
|
|
name: Path(value[name]) for name in (
|
|
'historical_root', 'controller_workspace', 'authoritative_git_dir',
|
|
'runtime_registry_root', 'runtime_baseline_path', 'trusted_release_policy_path',
|
|
)
|
|
}
|
|
owner_key_id = value['owner_key_id']
|
|
try:
|
|
owner_key_valid = (isinstance(owner_key_id, str)
|
|
and owner_key_id.startswith('SHA256:')
|
|
and len(base64.b64decode(owner_key_id[7:], validate=True)) == 32)
|
|
except (ValueError, TypeError):
|
|
owner_key_valid = False
|
|
all_paths = (authority_root, state_root, *governed_paths.values())
|
|
if (any(not item.is_absolute() or '..' in item.parts for item in all_paths)
|
|
or not _sha(value['predecessor_fingerprint']) or not _sha(value['saga_head'])
|
|
or not _sha(value['trusted_release_policy_sha256'])
|
|
or not owner_key_valid):
|
|
raise RenewalRejected('COMPLETION_BINDINGS_VALUE_INVALID')
|
|
if path.parent != authority_root:
|
|
raise RenewalRejected('COMPLETION_BINDINGS_ROOT_MISMATCH')
|
|
global AUTHORITY_ROOT, STATE_ROOT, OWNER_KEY, OLD_FP, SAGA_HEAD
|
|
global HISTORICAL_ROOT, CONTROLLER_WORKSPACE, AUTHORITATIVE_GIT_DIR
|
|
global RUNTIME_REGISTRY_ROOT, RUNTIME_BASELINE_PATH
|
|
global TRUSTED_RELEASE_POLICY_PATH, TRUSTED_RELEASE_POLICY_SHA256
|
|
AUTHORITY_ROOT = authority_root
|
|
STATE_ROOT = state_root
|
|
OWNER_KEY = value['owner_key_id']
|
|
OLD_FP = value['predecessor_fingerprint']
|
|
SAGA_HEAD = value['saga_head']
|
|
HISTORICAL_ROOT = governed_paths['historical_root']
|
|
CONTROLLER_WORKSPACE = governed_paths['controller_workspace']
|
|
AUTHORITATIVE_GIT_DIR = governed_paths['authoritative_git_dir']
|
|
RUNTIME_REGISTRY_ROOT = governed_paths['runtime_registry_root']
|
|
RUNTIME_BASELINE_PATH = governed_paths['runtime_baseline_path']
|
|
TRUSTED_RELEASE_POLICY_PATH = governed_paths['trusted_release_policy_path']
|
|
TRUSTED_RELEASE_POLICY_SHA256 = value['trusted_release_policy_sha256']
|
|
_BINDINGS_DIGEST = expected_sha256
|
|
return dict(value)
|
|
|
|
|
|
class RegisteredCompletionAuthority:
|
|
"""Fixed root registration, Owner signature and immutable evidence verifier.
|
|
|
|
The completed production proofs are historical facts. This fresh authority
|
|
permits only approval renewal and remaining metadata effects; it cannot
|
|
authorize another runtime switch or public acceptance Task.
|
|
"""
|
|
|
|
@property
|
|
def root(self):
|
|
return AUTHORITY_ROOT
|
|
|
|
@property
|
|
def state_root(self):
|
|
return STATE_ROOT
|
|
|
|
def __call__(self):
|
|
from c5_staging_installation import RegistryOwnerVerifier
|
|
root = AUTHORITY_ROOT
|
|
_safe_parents(root / 'contract.json')
|
|
envelope = json.loads(secure_bytes(root / 'contract.json'))
|
|
if set(envelope) != {'payload', 'signature'}:
|
|
raise RenewalRejected('EXACT_AUTHORITY_ENVELOPE_REQUIRED')
|
|
p = envelope['payload']
|
|
fields = {'schema', 'host', 'repository', 'candidate_id', 'source_commit', 'tree_oid',
|
|
'artifact_sha256', 'release_plan_sha256', 'state_root', 'predecessor_fingerprint',
|
|
'predecessor_sha256', 'predecessor_uid', 'predecessor_snapshot', 'approval_nonce',
|
|
'issued_at', 'expires_at', 'owner_key_id', 'owner_namespace', 'allowed_effects',
|
|
'runtime_effects_allowed', 'files', 'gate_path', 'gate_observed_at',
|
|
'governed_source_commit', 'governed_source_tree'}
|
|
if not isinstance(p, dict) or set(p) != fields:
|
|
raise RenewalRejected('EXACT_AUTHORITY_SCHEMA_REQUIRED')
|
|
exact = {'schema': 'aios.c5.registered-completion-authority.v1', 'host': 'cn-network-mkt',
|
|
'repository': 'aios/aios', 'candidate_id': CID, 'source_commit': SOURCE,
|
|
'tree_oid': TREE, 'artifact_sha256': ARTIFACT, 'release_plan_sha256': PLAN,
|
|
'state_root': str(STATE_ROOT), 'predecessor_fingerprint': OLD_FP,
|
|
'owner_key_id': OWNER_KEY, 'owner_namespace': 'aios-owner-approval-v1',
|
|
'allowed_effects': ['approval_successor_append', 'baseline_finalize', 'registry_finalize', 'tag_publish'],
|
|
'runtime_effects_allowed': False}
|
|
if any(p[k] != v for k, v in exact.items()) or type(p['runtime_effects_allowed']) is not bool:
|
|
raise RenewalRejected('EXACT_COMPLETION_AUTHORITY_REQUIRED')
|
|
now = time.time()
|
|
if (type(p['issued_at']) is not int or type(p['expires_at']) is not int
|
|
or not p['issued_at'] <= now < p['expires_at']
|
|
or not 0 < p['expires_at'] - p['issued_at'] <= 1800
|
|
or type(p['gate_observed_at']) not in {int, float}
|
|
or not math.isfinite(p['gate_observed_at'])
|
|
or not p['issued_at'] - 60 <= p['gate_observed_at'] <= p['issued_at']):
|
|
raise RenewalRejected('FRESH_OWNER_AUTHORITY_REQUIRED')
|
|
if (not _sha(p['approval_nonce']) or not _sha(p['predecessor_sha256'])
|
|
or type(p['predecessor_uid']) is not int or p['predecessor_uid'] not in {0, 1000}
|
|
or any(not isinstance(p[k], str) or len(p[k]) != 40
|
|
or any(c not in '0123456789abcdef' for c in p[k])
|
|
for k in ('governed_source_commit', 'governed_source_tree'))):
|
|
raise RenewalRejected('AUTHORITY_IDENTITIES_INVALID')
|
|
verifier = RegistryOwnerVerifier(Path('/etc/aios/single-host-signer-registry.json'),
|
|
owner_signer_id='local-owner-authority')
|
|
if not verifier.verify(namespace=p['owner_namespace'], payload=canonical(p),
|
|
signature=envelope['signature'], key_id=p['owner_key_id']):
|
|
raise RenewalRejected('OWNER_SIGNATURE_REJECTED')
|
|
payload_sha = digest(canonical(p))
|
|
registered = json.loads(secure_bytes(root / 'registration.json'))
|
|
if (set(registered) != {'schema', 'status', 'payload_sha256', 'approval_nonce'}
|
|
or registered != {'schema': 'aios.c5.completion-registration.v1', 'status': 'REGISTERED',
|
|
'payload_sha256': payload_sha, 'approval_nonce': p['approval_nonce']}):
|
|
raise RenewalRejected('ROOT_REGISTRATION_REQUIRED')
|
|
if (root / 'rollback.json').exists():
|
|
raise RenewalRejected('REGISTRATION_ROLLED_BACK')
|
|
pins = p['files']
|
|
if not isinstance(pins, list) or not pins:
|
|
raise RenewalRejected('SIGNED_FILE_CLOSURE_REQUIRED')
|
|
checked = {}
|
|
for item in pins:
|
|
if (not isinstance(item, dict) or set(item) != {'path', 'sha256', 'uid'}
|
|
or not _sha(item['sha256']) or type(item['uid']) is not int or item['uid'] != 0):
|
|
raise RenewalRejected('SIGNED_FILE_PIN_INVALID')
|
|
path = Path(item['path'])
|
|
if path.parent != root or str(path) in checked:
|
|
raise RenewalRejected('SIGNED_FILE_PATH_INVALID')
|
|
_safe_parents(path)
|
|
raw = secure_bytes(path)
|
|
if digest(raw) != item['sha256']:
|
|
raise RenewalRejected('SIGNED_FILE_BYTES_DRIFT')
|
|
checked[str(path)] = raw
|
|
required = {str(root / name) for name in (*RENEWAL_SOURCE_FILES, *PHASE_DEPENDENCIES, 'source-material.json',
|
|
'historical-production-proof.json', 'predecessor-approval.json', 'current-gate.json',
|
|
'approval-public-keyring.json', 'original_api.py')}
|
|
if not required <= set(checked):
|
|
raise RenewalRejected('INCOMPLETE_REGISTERED_CLOSURE')
|
|
if Path(__file__) != root / 'c5_completion_renewal.py':
|
|
raise RenewalRejected('UNREGISTERED_AUTHORITY_MODULE')
|
|
if (p['predecessor_snapshot'] != str(root / 'predecessor-approval.json')
|
|
or p['gate_path'] != str(root / 'current-gate.json')
|
|
or digest(checked[p['predecessor_snapshot']]) != p['predecessor_sha256']):
|
|
raise RenewalRejected('REGISTERED_SNAPSHOT_DRIFT')
|
|
material = json.loads(checked[str(root / 'source-material.json')])
|
|
if (material.get('status') != 'MATERIALIZED' or material.get('task_status') != 'SUCCEEDED'
|
|
or material.get('remote_verified') is not True
|
|
or material.get('source_commit') != p['governed_source_commit']
|
|
or material.get('source_tree') != p['governed_source_tree']
|
|
or material.get('file_sha256') != {
|
|
name: digest(checked[str(root / name)])
|
|
for name in RENEWAL_SOURCE_FILES}):
|
|
raise RenewalRejected('GOVERNED_CODE_PROVENANCE_REQUIRED')
|
|
historical = json.loads(checked[str(root / 'historical-production-proof.json')])
|
|
if (historical.get('candidate_id') != CID or historical.get('approval_fingerprint') != OLD_FP
|
|
or historical.get('release_plan_sha256') != PLAN
|
|
or historical.get('status') != 'COMPLETED'
|
|
or any(historical.get(k) is not True for k in (
|
|
'public_business_verified', 'real_c4_rollback_verified', 'c5_restore_verified'))):
|
|
raise RenewalRejected('COMPLETED_PRODUCTION_PROOF_REQUIRED')
|
|
gate = json.loads(checked[p['gate_path']])
|
|
expected_gate = {'candidate_id': CID, 'source_commit': SOURCE, 'artifact_sha256': ARTIFACT,
|
|
'release_plan_sha256': PLAN,
|
|
'local_tag_oid': TAG_OID, 'runtime_verified': True, 'business_verified': True,
|
|
'global_writes_enabled': False, 'observed_at': p['gate_observed_at']}
|
|
if (any(gate.get(k) != v for k, v in expected_gate.items())
|
|
or any(type(gate.get(k)) is not bool for k in (
|
|
'runtime_verified', 'business_verified', 'global_writes_enabled'))
|
|
or gate.get('remote_tag_oid') not in {None, TAG_OID}):
|
|
raise RenewalRejected('EXACT_POSTVERIFICATION_GATE_REQUIRED')
|
|
validate_completion_lineage(gate)
|
|
return {**p, 'payload_sha256': payload_sha}
|
|
|
|
def validate_host(self, *, state_root, candidate_id, source_commit, tree_oid,
|
|
artifact_sha256, release_plan_sha256):
|
|
self()
|
|
if (Path(state_root), candidate_id, source_commit, tree_oid, artifact_sha256, release_plan_sha256) != (
|
|
STATE_ROOT, CID, SOURCE, TREE, ARTIFACT, PLAN):
|
|
raise RenewalRejected('COMPLETION_HOST_BINDING_DRIFT')
|
|
|
|
def deny_runtime_effect(self, **kwargs):
|
|
self()
|
|
raise RenewalRejected('COMPLETION_RUNTIME_EFFECT_FORBIDDEN')
|
|
|
|
|
|
class CompletionRuntimeGuard:
|
|
def __init__(self, authority):
|
|
if type(authority) is not RegisteredCompletionAuthority:
|
|
raise RenewalRejected('REGISTERED_COMPLETION_AUTHORITY_REQUIRED')
|
|
self.authority = authority
|
|
|
|
def execute(self, **kwargs):
|
|
return self.authority.deny_runtime_effect(**kwargs)
|
|
|
|
|
|
def append_file(path, raw):
|
|
"""An existing record must be identical; it is never replaced."""
|
|
path = Path(path)
|
|
try:
|
|
fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW, 0o600)
|
|
except FileExistsError:
|
|
if secure_bytes(path, owner_uid=os.geteuid()) != raw:
|
|
raise RenewalRejected('APPEND_ONLY_RECORD_CONFLICT')
|
|
return False
|
|
with os.fdopen(fd, 'wb') as stream:
|
|
stream.write(raw)
|
|
stream.flush()
|
|
os.fsync(stream.fileno())
|
|
fd = os.open(path.parent, os.O_DIRECTORY)
|
|
try:
|
|
os.fsync(fd)
|
|
finally:
|
|
os.close(fd)
|
|
return True
|
|
|
|
|
|
def publish_successor(directory, old, new, public_key, *, now, registration_digest, predecessor_bytes):
|
|
"""Append records inside the SAME plane under a verified caller lock.
|
|
|
|
Registration validation, current Saga CAS, production/business readbacks,
|
|
and permission to call this function remain mandatory caller gates.
|
|
"""
|
|
fp = validate_successor(old, new, public_key, now=now)
|
|
if json.loads(predecessor_bytes) != old:
|
|
raise RenewalRejected('PREDECESSOR_BYTES_DRIFT')
|
|
predecessor_bytes_digest = digest(predecessor_bytes)
|
|
if len(registration_digest) != 64 or any(c not in '0123456789abcdef' for c in registration_digest):
|
|
raise RenewalRejected('REGISTERED_DIGEST_REQUIRED')
|
|
directory = Path(directory)
|
|
metadata = directory.lstat()
|
|
if not stat.S_ISDIR(metadata.st_mode) or metadata.st_uid != os.geteuid() or metadata.st_mode & 0o022:
|
|
raise RenewalRejected('UNSAFE_APPEND_DIRECTORY')
|
|
receipt = {'schema': 'aios.c5.completion-approval-successor.v1', 'candidate_id': CID,
|
|
'predecessor_fingerprint': OLD_FP, 'predecessor_bytes_sha256': predecessor_bytes_digest,
|
|
'successor_fingerprint': fp, 'successor_sha256': digest(canonical(new)),
|
|
'owner_registration_payload_sha256': registration_digest,
|
|
'completion_only': True, 'runtime_effects_allowed': False}
|
|
# A crash after the first append is unresolved until its exact receipt is
|
|
# reconciled. A loader must require BOTH files; no mutable current pointer.
|
|
append_file(directory / (fp + '.approval.json'), canonical(new))
|
|
append_file(directory / (fp + '.receipt.json'), canonical(receipt))
|
|
return receipt
|
|
|
|
|
|
class CompletionApprovalStore:
|
|
"""Explicit store dependency for a registered completion host/API.
|
|
|
|
The original store and original candidate approval remain untouched.
|
|
No global class replacement or expired approval verification is used.
|
|
An authenticated registration fixes ONE successor nonce and immutable
|
|
receipt path before signing. The host must separately enforce TAG_PENDING
|
|
and forbid runtime effects; this store does not execute a Saga.
|
|
"""
|
|
|
|
def __init__(self, original, directory, public_key, authority, approval_type):
|
|
self.original = original
|
|
self.directory = Path(directory)
|
|
self.public_key = public_key
|
|
self.authority = authority
|
|
self.approval_type = approval_type
|
|
|
|
def _policy(self):
|
|
# authority must be the fixed registered verifier, not a caller-supplied
|
|
# HTTP callback. Wiring it is outside this unregistered draft.
|
|
policy = self.authority()
|
|
if policy.get('candidate_id') != CID or policy.get('predecessor_fingerprint') != OLD_FP:
|
|
raise RenewalRejected('REGISTERED_EXACT_POLICY_REQUIRED')
|
|
nonce = policy.get('approval_nonce', '')
|
|
if not isinstance(nonce, str) or len(nonce) != 64 or any(c not in '0123456789abcdef' for c in nonce):
|
|
raise RenewalRejected('REGISTERED_NONCE_REQUIRED')
|
|
return policy, self.directory / (nonce + '.activation.json')
|
|
|
|
def _parent(self):
|
|
old = self.original.load(CID)
|
|
policy, _ = self._policy()
|
|
owner = policy.get('predecessor_uid')
|
|
if type(owner) is not int or owner not in {0, 1000}:
|
|
raise RenewalRejected('REGISTERED_PREDECESSOR_OWNER_REQUIRED')
|
|
raw = secure_bytes(self.original.root / (CID + '.json'), owner_uid=owner)
|
|
if json.loads(raw) != old.to_dict() or digest(raw) != policy.get('predecessor_sha256'):
|
|
raise RenewalRejected('PREDECESSOR_FILE_DRIFT')
|
|
return old.to_dict(), raw
|
|
|
|
def load(self, candidate_id):
|
|
if candidate_id != CID:
|
|
return self.original.load(candidate_id)
|
|
policy, activation = self._policy()
|
|
if not activation.exists():
|
|
return self.original.load(candidate_id)
|
|
receipt = json.loads(secure_bytes(activation, owner_uid=policy['predecessor_uid']))
|
|
expected = {'schema', 'candidate_id', 'predecessor_fingerprint', 'predecessor_bytes_sha256',
|
|
'successor_fingerprint', 'successor_sha256', 'owner_registration_payload_sha256',
|
|
'completion_only', 'runtime_effects_allowed'}
|
|
if set(receipt) != expected or receipt.get('owner_registration_payload_sha256') != policy['payload_sha256']:
|
|
raise RenewalRejected('ACTIVATION_RECEIPT_INVALID')
|
|
fp = receipt.get('successor_fingerprint', '')
|
|
if len(fp) != 64 or any(c not in '0123456789abcdef' for c in fp):
|
|
raise RenewalRejected('SUCCESSOR_FINGERPRINT_INVALID')
|
|
raw = secure_bytes(self.directory / (fp + '.approval.json'), owner_uid=policy['predecessor_uid'])
|
|
new = json.loads(raw)
|
|
parent, parent_raw = self._parent()
|
|
valid = validate_successor(parent, new, self.public_key, now=datetime.now(timezone.utc).timestamp())
|
|
exact = {'candidate_id': CID, 'predecessor_fingerprint': OLD_FP,
|
|
'predecessor_bytes_sha256': digest(parent_raw), 'successor_fingerprint': valid,
|
|
'successor_sha256': digest(raw), 'completion_only': True, 'runtime_effects_allowed': False}
|
|
if any(receipt.get(k) != v for k, v in exact.items()) or new['nonce'] != policy['approval_nonce']:
|
|
raise RenewalRejected('SUCCESSOR_ACTIVATION_DRIFT')
|
|
durable = json.loads(secure_bytes(self.directory / (fp + '.receipt.json'), owner_uid=policy['predecessor_uid']))
|
|
if durable != receipt:
|
|
raise RenewalRejected('DURABLE_RECEIPT_DRIFT')
|
|
return self.approval_type.from_dict(new)
|
|
|
|
def save(self, candidate_id, approval):
|
|
if candidate_id != CID:
|
|
return self.original.save(candidate_id, approval)
|
|
policy, activation = self._policy()
|
|
parent, raw = self._parent()
|
|
if approval.fingerprint == parent['fingerprint']:
|
|
return self.original.save(candidate_id, approval)
|
|
new = approval.to_dict()
|
|
if new.get('nonce') != policy['approval_nonce']:
|
|
raise RenewalRejected('REGISTERED_NONCE_MISMATCH')
|
|
# The caller supplies its authenticated registered effect lock and
|
|
# invokes the existing ApprovalVerifier before this store boundary.
|
|
receipt = publish_successor(self.directory, parent, new, self.public_key,
|
|
now=datetime.now(timezone.utc).timestamp(),
|
|
registration_digest=policy['payload_sha256'], predecessor_bytes=raw)
|
|
created = append_file(activation, canonical(receipt))
|
|
if self.load(candidate_id).fingerprint != approval.fingerprint:
|
|
raise RenewalRejected('SUCCESSOR_READBACK_FAILED')
|
|
return activation, created
|
|
|
|
|
|
class RegisteredCompletionApprovalStore(CompletionApprovalStore):
|
|
"""Production dependency; no request-selected root or authority callback."""
|
|
|
|
def __init__(self, original, public_key, approval_type):
|
|
if Path(original.root) != STATE_ROOT / 'approvals':
|
|
raise RenewalRejected('SAME_APPROVAL_PLANE_REQUIRED')
|
|
super().__init__(original, STATE_ROOT / 'approvals' / 'c5-completion-successors',
|
|
public_key, RegisteredCompletionAuthority(), approval_type)
|
|
|
|
|
|
class CompletionSignerMixin:
|
|
"""Narrow additional method of the EXISTING credential-bound signer.
|
|
|
|
Activation must register this exact mixin, verifier and namespace snapshot
|
|
pins. The encrypted private key stays in the existing signer's unit. This
|
|
draft supplies no activation, credential access or HTTP route.
|
|
"""
|
|
|
|
def sign_exact_completion_successor(self, request):
|
|
expected = {'schema', 'operation', 'candidate_id', 'predecessor_fingerprint'}
|
|
if (set(request) != expected or request.get('operation') != 'renew_exact_completion_approval'
|
|
or request.get('candidate_id') != CID or request.get('predecessor_fingerprint') != OLD_FP
|
|
or request.get('schema') != 'aios.exact-release-signer.request.v1'):
|
|
raise RenewalRejected('EXACT_SIGNER_RENEWAL_REQUEST_REQUIRED')
|
|
policy = self.completion_authority()
|
|
now = datetime.now(timezone.utc).timestamp()
|
|
if (policy.get('candidate_id') != CID or policy.get('predecessor_fingerprint') != OLD_FP
|
|
or not policy['issued_at'] <= now < policy['expires_at']
|
|
or not 0 <= now - policy['gate_observed_at'] <= 60):
|
|
raise RenewalRejected('FRESH_REGISTERED_COMPLETION_GATE_REQUIRED')
|
|
old_raw = secure_bytes(policy['predecessor_snapshot'], owner_uid=0)
|
|
if digest(old_raw) != policy['predecessor_sha256']:
|
|
raise RenewalRejected('REGISTERED_SIGNER_PREIMAGE_DRIFT')
|
|
old = json.loads(old_raw)
|
|
public_key = self.private_key.public_key().public_bytes(Encoding.Raw, PublicFormat.Raw)
|
|
verify_signature(old, public_key)
|
|
exact = {'candidate_id': CID, 'source_commit': SOURCE, 'tree_oid': TREE,
|
|
'artifact_sha256': ARTIFACT, 'release_plan_sha256': PLAN,
|
|
'fingerprint': OLD_FP, 'capabilities': CAPABILITIES,
|
|
'key_id': self.policy.key_id, 'owner_identity': self.policy.owner_identity,
|
|
'trust_domain': self.policy.trust_domain,
|
|
'owner_approval_record_oid': self.authorization_oid}
|
|
if any(old.get(k) != v for k, v in exact.items()) or timestamp(old['expires_at']) > now:
|
|
raise RenewalRejected('EXACT_EXPIRED_SIGNER_PREDECESSOR_REQUIRED')
|
|
nonce = policy['approval_nonce']
|
|
if len(nonce) != 64 or any(c not in '0123456789abcdef' for c in nonce) or nonce == old['nonce']:
|
|
raise RenewalRejected('FRESH_REGISTERED_SIGNER_NONCE_REQUIRED')
|
|
output = self.state_root / 'completion-renewals' / (nonce + '.json')
|
|
if output.exists():
|
|
result = json.loads(secure_bytes(output, owner_uid=0))
|
|
if (result.get('registration_payload_sha256') != policy['payload_sha256']
|
|
or result['approval']['nonce'] != nonce):
|
|
raise RenewalRejected('SIGNER_REPLAY_CONFLICT')
|
|
validate_successor(old, result['approval'], public_key, now=now)
|
|
return {**result, 'status': 'SIGNED_IDEMPOTENT'}
|
|
expiry = min(now + 600, policy['expires_at'] - 5)
|
|
if expiry - now < 120:
|
|
raise RenewalRejected('INSUFFICIENT_SIGNER_WINDOW')
|
|
def utc(value):
|
|
return datetime.fromtimestamp(value, timezone.utc).replace(microsecond=0).isoformat().replace('+00:00', 'Z')
|
|
payload = {k:v for k,v in old.items() if k not in {'fingerprint', 'signature'}}
|
|
payload.update(issued_at=utc(now), not_before=utc(now), expires_at=utc(expiry), nonce=nonce)
|
|
raw = canonical(payload)
|
|
# All candidate, plan, historical signature and registered freshness
|
|
# checks precede this only signing operation.
|
|
approval = {**payload, 'fingerprint': digest(raw),
|
|
'signature': base64.b64encode(self.private_key.sign(raw)).decode()}
|
|
validate_successor(old, approval, public_key, now=now)
|
|
result = {'schema': 'aios.exact-release-signer.response.v1', 'status': 'SIGNED',
|
|
'approval': approval, 'registration_payload_sha256': policy['payload_sha256'],
|
|
'predecessor_fingerprint': OLD_FP, 'completion_only': True, 'arbitrary_signing': False}
|
|
# This registered directory must be created by the activation consumer
|
|
# inside the existing signer state root, never a request path.
|
|
append_file(output, canonical(result))
|
|
return result
|