"""Shared accepted D09 grammar; transport authentication belongs to the caller. Installed beside both fixed entrypoints in /usr/libexec. The schema is pinned, not selectable by a requester. No test-only contract checker is imported. """ import hashlib import json import pathlib import re SCHEMA_SHA256 = '2e293bf7481c8442b40521a5960467fc4a83913ff5d8a3832b05aa6e49d23839' MAX = 65536 def canonical(value): return json.dumps(value, sort_keys=True, separators=(',', ':'), ensure_ascii=True, allow_nan=False).encode('ascii') def digest(raw): return hashlib.sha256(raw).hexdigest() def release_digest(identity): """Archive domain, deliberately distinct from protected object_digest. The external admission attests the mapping of these downloaded components to objects.new (including runtime extraction and preserved frontend assets). URLs, mirror choice and the downloader's current version are not identity. """ if type(identity) is not list or len(identity) != 2: raise ValueError('release identity') version, components = identity def token(value): return type(value) is str and re.fullmatch('[A-Za-z0-9_.+-]{1,128}', value) if not token(version) or type(components) is not list or not 1 <= len(components) <= 16: raise ValueError('release identity bounds') names = [] for item in components: if type(item) is not list or len(item) != 4: raise ValueError('component identity') name, version, hashed, size = item if not token(name) or not token(version) or type(hashed) is not str or not re.fullmatch('[0-9a-f]{64}', hashed) or type(size) is not int or not 0 < size <= 9007199254740991: raise ValueError('component identity fields') names.append(name) if names != sorted(set(names)): raise ValueError('component ordering/duplicates') return digest(canonical(identity)) def pairs(items): result = {} for key, value in items: if key in result: raise ValueError('duplicate field') result[key] = value return result def reject(value): raise ValueError('noncanonical number') def parse(raw): if not raw or len(raw) > MAX: raise ValueError('wire size') try: value = json.loads(raw.decode('ascii'), object_pairs_hook=pairs, parse_float=reject, parse_constant=reject) except RecursionError as exc: raise ValueError('wire depth') from exc if canonical(value) != raw: raise ValueError('noncanonical bytes') def depth(item, level=1): if level > 8: raise ValueError('wire depth') if isinstance(item, dict): for child in item.values(): depth(child, level + 1) elif isinstance(item, list): for child in item: depth(child, level + 1) depth(value) return value def schema(): raw = pathlib.Path(__file__).with_name('d09-wire-schema.json').read_bytes() if digest(raw) != SCHEMA_SHA256: raise ValueError('unreviewed D09 schema') return json.loads(raw) def validate(record, value): grammar = schema() def check(rule, item): if isinstance(rule, str): rule = grammar['definitions'][rule] kind = rule['kind'] if kind == 'record': validate(rule['of'], item) elif kind == 'object': optional = rule.get('optional_fields', {}) if (type(item) is not dict or not set(rule['exact_fields']) <= set(item) or not set(item) <= set(rule['exact_fields']) | set(optional)): raise ValueError('exact fields') for key, subrule in rule['exact_fields'].items(): check(subrule, item[key]) for key, subrule in optional.items(): if key in item: check(subrule, item[key]) elif kind == 'boolean': if type(item) is not bool: raise ValueError('boolean') elif kind == 'string': if type(item) is not str or not 0 < len(item) <= rule['maximum'] or not all(32 <= ord(c) <= 126 for c in item): raise ValueError('bounded text') elif kind == 'nullable': if item is not None: check(rule['of'], item) elif kind == 'integer': if type(item) is not int or not rule['minimum'] <= item <= rule['maximum']: raise ValueError('bounded integer') elif kind == 'constant': if type(item) is not type(rule['value']) or item != rule['value']: raise ValueError('constant') elif kind == 'enum': if type(item) is not str or item not in rule['values']: raise ValueError('enum') elif kind == 'hex': if type(item) is not str or not re.fullmatch('[0-9a-f]{%d}' % rule['length'], item): raise ValueError('hex') if rule['nonzero'] and int(item, 16) == 0: raise ValueError('zero identifier') else: raise ValueError('unknown grammar') check(grammar['records'][record], value) if record == 'inspect_response' and 'os_update' in value: validate_os_status(value['os_update']) if record == 'submit_request': routes = {'UPDATER': ('APPLY', 'APPLY_REQUEST'), 'AUTOMATIC': ('RECOVER', 'AUTOMATIC_FAILURE'), 'MANUAL': ('RECOVER', 'MANUAL_REQUEST'), 'GUARD': ('RECOVER', 'CRASH_NOTICE'), 'BOOT': ('RECOVER', 'BOOT_RECONCILE'), 'OBSERVER': ('ACK_OBSERVATION', 'OBSERVATION_READY')} if routes[value['route']] != (value['operation'], value['reason']): raise ValueError('route binding') if (value['requester_invocation_id'] is None) != (value['route'] in ('BOOT', 'OBSERVER')): raise ValueError('invocation nullability') if (value['observer_receipt_digest'] is not None) != (value['operation'] == 'ACK_OBSERVATION'): raise ValueError('observer nullability') if (value['selected_release_digest'] is not None) != (value['operation'] == 'APPLY'): raise ValueError('selected release nullability') if (value['staging_generation'] is not None) != (value['operation'] == 'APPLY'): raise ValueError('staging generation nullability') if record == 'receipt': if (value['previous_receipt_digest'] is None) != (value['sequence'] == 1): raise ValueError('predecessor') if value['outcome'] == 'COMPLETE': if value['phase'] not in ('COMPLETE', 'CLEANUP_INTENT', 'RETAINED'): raise ValueError('completion phase') for key in ('executor', 'observed_invocation_id', 'namespace_observation_digest', 'preservation_observation_digest', 'effective_config_observation_digest', 'config_pre_digest', 'config_post_digest', 'config_current_digest'): if value[key] is None: raise ValueError('incomplete observation') return value def validate_os_status(status): confirmed = status['phase'] == 'POSTBOOT_CONFIRMED' if status['post_boot_verified'] != confirmed: raise ValueError('OS postboot disposition') if confirmed and (status['reboot_required'] is not False or not status['installed_kernel'] or status['installed_kernel'] != status['running_kernel']): raise ValueError('OS kernel not confirmed') if status['phase'] == 'REBOOT_REQUIRED' and status['reboot_required'] is not True: raise ValueError('OS reboot disposition') if status['phase'] not in ('NO_OS_TRANSACTION', 'UNKNOWN') and (not status['supported'] or status['plan_sha256'] is None): raise ValueError('OS plan/capability missing') return status def decode(record, raw): return validate(record, parse(raw)) def bind_submit(request, response): """Cross-bind a response received on the live, pinned authenticated channel. Only the owner can authenticate the protected acceptance and current head; these checks are in addition to, never a substitute for, peer authentication. """ validate('submit_response', response) hashed = digest(canonical(request)) if response['status'] == 'REFUSED': if response['outcome'] != 'REFUSED' or any(response[k] is not None for k in ('acceptance', 'receipt', 'receipt_digest')): raise ValueError('refusal shape') return response a, r = response['acceptance'], response['receipt'] if not a or not r or response['reservation'] != 'RETAINED': raise ValueError('missing authenticated acceptance/head') validate('receipt', r) if response['request_digest'] != hashed or a['request_digest'] != hashed: raise ValueError('request digest') for key in ('operation', 'request_id', 'transaction_id', 'target_binding_digest', 'composition_digest', 'grant_digest'): if a[key] != request[key]: raise ValueError('acceptance binding') for key in ('transaction_id', 'target_binding_digest', 'composition_digest'): if a[key] != r[key]: raise ValueError('head binding') if a['accepted_sequence'] > r['sequence']: raise ValueError('head precedes acceptance') if a['accepted_sequence'] == r['sequence'] and any(a[k] != r[k] for k in ('operation', 'request_digest')): raise ValueError('equal sequence identity') if response['receipt_digest'] != digest(canonical(r)) or response['outcome'] != r['outcome']: raise ValueError('receipt binding') return response def bind_inspect(request, response): validate('inspect_response', response) for key in ('challenge', 'target_binding_digest'): if request[key] != response[key]: raise ValueError('inspect challenge/target') r = response['receipt'] if response['status'] == 'TRANSACTION': if not r: raise ValueError('missing head') validate('receipt', r) if request['transaction_id'] not in (None, r['transaction_id']): raise ValueError('inspect transaction') for key in ('transaction_id', 'target_binding_digest', 'admission_epoch_id'): if response[key] != r[key]: raise ValueError('inspect identity') if response['head_sequence'] != r['sequence'] or response['receipt_digest'] != digest(canonical(r)) or response['head_digest'] != response['receipt_digest']: raise ValueError('inspect head') elif any(response[k] is not None for k in ('receipt', 'receipt_digest')): raise ValueError('absent receipt') if response['status'] == 'UNKNOWN' and any(response[k] is not None for k in ('head_digest', 'head_sequence', 'admission_epoch_id')): raise ValueError('unknown continuity') return response