diff --git a/docs/reviews/2026-10-11-key39-node-route-platform-review.json b/docs/reviews/2026-10-11-key39-node-route-platform-review.json new file mode 100644 index 0000000..b25f506 --- /dev/null +++ b/docs/reviews/2026-10-11-key39-node-route-platform-review.json @@ -0,0 +1,65 @@ +{ + "completed_same_owner_refinement_precedes_formal_review": true, + "decision": "approved", + "input_unchanged": true, + "intent_basis": "Platform INTENT stable shared interfaces, secure custody and observable recovery: exact provider route prerequisites and fail-closed guarded native preparation without publichealth becoming authority.", + "mandatory_native_prerequisites": [ + "Publichealth clusterhash is unauthenticated: independently verify founder/node/Service/cluster/provider route identity, current admitted route/estate and exact source/runtime pins; no arbitrary workstation diagnostic proves node placement.", + "Actual installed OpenBao JWT plugin/version, role/config/effective-policy source equality and raw/effective expiration_leeway, clock_skew_leeway and not_before_leeway interaction. Helm2.5.4/tag and raw0=>150 model are not native facts; semantic expiry proof remains mandatory.", + "Establish issuer actual readiness_state and Argo ownership through authoritative source/owner receipt. No keycape declaration/current deployment adoption established in inspected sources; absence is not nonproduction. Unmapped production-tier rules apply. If adopted/production-approved, transient directCAS needs explicit reviewed one-use maintenanceexception, close-down entry and reconciliation before nativego.", + "Fresh authenticated scoped founder decision covers exact route, source, issuer mutation/window and finite abort/revoke/restoration/recovery obligations. Helper labels/sourceacknowledgments cannot authenticate approval or waive gates.", + "Admitted private founder human/coding-agent token producer/client/callback/custody handoff remains unimplemented. No credential request/read/reuse authorized.", + "Native correct role/claim permutation/expiry/refusal/revoke, baseline restoration/client removal/temporaryobject absence and all unknown outcome resolution. MASON and Secrets native/full-adoption obligations stay separate." + ], + "not_approved": [ + "route setup, native preflight/login/Secret access or production mutation", + "privileged authority/helperapproval authentication or default flip", + "current provider identity/plugin/leeway/readiness/Argo facts", + "private producer or whole KEY39/RPF35T02/SecretsT06 native acceptance" + ], + "optional_consumer_consistency_observation": { + "manifest_sha256": "32a419752e4a3ed7cf8f906fc40ebbaa516b9a4d6134be2df29243ce97213e40", + "notes": [ + "Explicit execute-ccr descriptor is shape/binding only; unimplemented compiler/adapter remains gate.", + "Consumer hashes use sha256: prefix; Journal Binding uses bare64hex. The future owner mediator must define and validate exact representation conversion; do not silently join mismatched identity/digests.", + "Execution request propagation does not satisfy caller/PDP/consume/plan/admission/body scope by itself." + ], + "scope": "Read design/schema for Platform interoperability only; no Secrets owner review" + }, + "ordering_caveat": "Documentation says execute checks health before protected token input, but main reads private stdin before execute invokes health. That claim is excluded from this approval. Before producer handoff/native admission, correct packet wording or implement a pre-input gate and review its exact source. Actual fail-before-native/Secret effects is verified.", + "platform_source_pins": { + "helm/openbao-ui-overlay-k8s.yaml": "7b345359906bf1ecc4cb8e61de7a9f1a121068a66bd919e606190a9217a82daf", + "helm/openbao-ui-overlay/nginx.conf": "464f7f5cecc69ea343c1e2acc5932e832b2a9c0e6a5099113634a12abc80ccb3", + "helm/openbao-values.yaml": "a10239851277889dd69dacb8636109dddd095551d85b46ca4ed2c141944e8d1e" + }, + "review_scope": "public-health fail-before-native gate and bounded node-route proposal source only; no native route/go or pre-private-input claim", + "reviewed_entries": { + "sso-mfa/k8s/keycape/openbao-negative-node-route.md": "b1184d349ad8166804253edeb7932b82d1bd30eb5fe46fcc5bbda8f88593eb9d", + "sso-mfa/k8s/keycape/openbao-negative-session.py": "11df42c873ee7ab4cf4a42fa2326ada4661703632b07745220e75a61f7c7fadf", + "sso-mfa/k8s/keycape/test_openbao_negative_session.py": "01e23f2b4fc77824a161a57acb3a52d19aad846b3b6c0fd3abd81afa1dc2985c", + "sso-mfa/k8s/keycape/test_openbao_node_route.py": "00e370b0c3892e16939b7e34ee070df7fe6183b8037741a33b7a6f2814847a9d" + }, + "reviewed_manifest": "/tmp/keycape-jwt-node-route-stage/manifest.json", + "reviewed_manifest_sha256": "23a972abc5175e121e594726d2b7f7a28c62109253f58f12623eaf2e5564a035", + "reviewer": "railiance-platform-owner (agent railiance-platform, codex)", + "same_trial": true, + "schema": "owner-source-review/v1", + "validation": { + "commands": [ + "PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s /tmp/keycape-jwt-node-route-stage/net-kingdom/sso-mfa/k8s/keycape -p test_openbao*.py -q", + "PYTHONDONTWRITEBYTECODE=1 /home/worsch/secrets-engine/.venv/bin/python -m pytest -q -p no:cacheprovider /tmp/platform-key39-node-route-review-stage/tests/test_platform_route.py" + ], + "independent_checks": 6, + "result": "passed synthetic/offline tests; native false", + "supplied_lifecycle_and_route": 54, + "total_fresh_checks": 60 + }, + "verified": [ + "SourceService openbao/openbao-ui-gateway8080 routes to nginx /v1 proxy for OpenBao8200; proposed dedicated node-loopback Service port-forward avoids node PodDNS assumption and shared workstation tunnel alteration. No portforward/bridge/native route executed.", + "PublicGET only fixed /v1/sys/health, no credential header; strict initialized/unsealed/active booleans and bounded cluster-id hash, no raw public id retained.", + "Current-process-only route-preflight performs no Kubernetes/Secret/private-stdin access, retains native_accepted=false.", + "Execute/recovery pin health before native reads; second health check after dry-runs before first create. Missing/drift/unavailable/redirect/slow response prevents protected effects.", + "Existing no-proxy/no-redirect/byte/mainthread-total-timer/finite-exception-abort bounds apply; failed cleanup/unknown login is not cleared by healthy route." + ], + "work_item": "RPF-WP-0035-T13" +} diff --git a/docs/reviews/2026-10-11-task-execution-journal-v2-platform-review.json b/docs/reviews/2026-10-11-task-execution-journal-v2-platform-review.json new file mode 100644 index 0000000..ac6bb30 --- /dev/null +++ b/docs/reviews/2026-10-11-task-execution-journal-v2-platform-review.json @@ -0,0 +1,48 @@ +{ + "completed_owner_record_precedes_formal_review": true, + "decision": "changes_requested", + "finding": { + "counterexamples": [ + "after_call(binding,False,correct_digest,evidence) confirms ordinal0", + "after_call(binding,0.0,correct_digest,evidence) confirms ordinal0", + "after_call(binding,'0',correct_digest,evidence) confirms ordinal0" + ], + "finding": "after_call lacks strict ordinal and call_digest validation; SQLite coerces ill-typed ordinal into exact stored integer, allowing pending outcome to be confirmed.", + "id": "RPF-JOURNAL-V2-F01", + "required_change": "Apply before_call equivalent exact integer0..63 and typed lowercase64hex call_digest validation before transaction; malformed confirmation must leave pending state unchanged. Retain no-live-admission and exact one-time confirmation checks." + }, + "inputs_unchanged": true, + "intent_basis": "Platform INTENT Stable Interfaces/Secure Custody/Operable recovery: exact durable admission and truthful unknown external outcomes, without source prototype becoming authority.", + "reviewed_files": { + "scripts/task_execution_journal.py": "86b912e98eaedfa172de0f805ceb572b8c787565d4d9bbfc09b5836289a4dc3a", + "tests/test_task_execution_journal.py": "01075296e57592ff30702cb9252c8b10133b26afe7921a084d5314107f9346c2" + }, + "reviewed_manifest": "/tmp/platform-execution-journal-stage-v2/manifest.json", + "reviewed_manifest_sha256": "341cac1de945d2fbe8f516119909bd44fc37e85dccfb38b451981d4de2d402e7", + "reviewer": "railiance-platform-owner (agent railiance-platform, codex)", + "schema": "owner-source-review/v1", + "scope_limits": [ + "Primitive does not authenticate caller, PDP/claim/consume or exact body plan; trusted owner mediation remains required.", + "Call ordinal/hash comes from future independent owner plan compiler; no generic backend/cleanup adapter or owner-private unknown recovery supplied.", + "Source syntax/state tests are not native grant, source application, whole execution-contract acceptance or RPF35-T12/SecretsT06 completion." + ], + "validation": { + "commands": [ + "PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s /tmp/platform-execution-journal-stage-v2/tests -q", + "PYTHONDONTWRITEBYTECODE=1 /home/worsch/secrets-engine/.venv/bin/python -m pytest -q -p no:cacheprovider /tmp/platform-journal-owner-review-stage/tests/test_independent_journal.py" + ], + "credential_access": false, + "independent_checks": 5, + "native": false, + "owner_checkout_writes": false, + "result": "19passed including3 deliberately reproduced malformed-confirmation defects, realfork crash and privatefile check", + "supplied_tests": 14 + }, + "verified_properties": [ + "Four actual processes contend and exactly one reserves the approval.", + "Private existing directory, database/lock modes, symlink/hardlink rejection, FULL SQLite durability and directory fsync.", + "Approval/operation uniqueness and full immutable binding; completed/unknown/reserved replay never reestablishes live admission.", + "Persisted pending call blocks next call and every success transition, including consume-confirmed, until exact confirmation; process crash after intent remains unknown/nonresumable." + ], + "work_item": "RPF-WP-0035-T11" +} diff --git a/docs/reviews/2026-10-11-task-execution-journal-v3-platform-review.json b/docs/reviews/2026-10-11-task-execution-journal-v3-platform-review.json new file mode 100644 index 0000000..8402423 --- /dev/null +++ b/docs/reviews/2026-10-11-task-execution-journal-v3-platform-review.json @@ -0,0 +1,49 @@ +{ + "completed_record_precedes_review": true, + "correction": "RPF-JOURNAL-V2-F01 corrected: exact integer0..63 and typed64hex call digest validated before after_call update, no SQLite bool/float/text ordinal coercion; malformed confirmations retain pending outcome then one correct confirmation passes.", + "decision": "approved", + "implementation_gates": [ + "Authenticate actual caller/representation and PDP/claim/consume; source methods do not authorize transitions.", + "Independent owner plan compiler pins exact ordinal/method/target/body hashes; call hashes alone prove no method/body scope.", + "Restricted native adapter, TTL/uses/deadline and owner-held grant/cleanup enforcement.", + "Owner-private cleanup/recovery after unknown remains unwired: business dispatch must not resume; cleanup needs a separately admitted bounded owner recovery interface.", + "Runtime private directory/credential isolation and actual native crash/refusal/revoke/readback proofs; source modes alone do not establish enforcement." + ], + "intent_basis": "Platform INTENT stable interfaces, secure custody and recovery: durable one-operation admission and truthful pending outcomes without a prototype becoming authority.", + "not_approved": [ + "native grants, production execution or source application", + "complete mediator/whole execution contract acceptance", + "RPF35-T12 or SecretsT06 closure or default migration" + ], + "prior_changes_requested_retained": true, + "prior_review": "docs/reviews/2026-10-11-task-execution-journal-v2-platform-review.json", + "prior_review_sha256": "3ed7894f0d5f7a648c61e1c15d7404786187cc40393f95f5fc4d866613da9459", + "review_scope": "unintegrated durable admission journal primitive source only", + "reviewed_files": { + "scripts/task_execution_journal.py": "866ac65af18ddabc5876cc940605d136bebfd8829fc467129d23ce2416b7716c", + "tests/test_task_execution_journal.py": "580ad0224038b9e800ac055c6650ba8b2346be1a93a32ce1a42b54ab4776bb91" + }, + "reviewed_input_unchanged": true, + "reviewed_manifest": "/tmp/platform-execution-journal-stage-v3/manifest.json", + "reviewed_manifest_sha256": "905ff6666d05df6a19d165a535579d917d7de31a43e066c2afc34a57e8cbdc9d", + "reviewer": "railiance-platform-owner (agent railiance-platform, codex)", + "same_trial": true, + "schema": "owner-source-review/v1", + "validated_properties": [ + "Actual4process race admits one operation only.", + "Real child-process abrupt exit after fsynced reservation/pending intent survives reopen as unknown/nonresumable.", + "Exclusive invocation, approval/operation uniqueness, immutable binding, exact call intent/confirmation and no terminal replay.", + "Private owner directory/SQLite/lock modes and no symlink/hardlink files; FULL SQLite commits and directory sync." + ], + "validation": { + "commands": [ + "PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s /tmp/platform-execution-journal-stage-v3/tests -q", + "PYTHONDONTWRITEBYTECODE=1 /home/worsch/secrets-engine/.venv/bin/python -m pytest -q -p no:cacheprovider /tmp/platform-journal-owner-review-stage/revision-v3/tests/test_independent_journal_v3.py" + ], + "independent_regressions": 5, + "result": "passed synthetic/local journal checks; no credentials/native action", + "supplied_tests": 15, + "total": 20 + }, + "work_item": "RPF-WP-0035-T11" +} diff --git a/scripts/task_execution_journal.py b/scripts/task_execution_journal.py new file mode 100644 index 0000000..b20975f --- /dev/null +++ b/scripts/task_execution_journal.py @@ -0,0 +1,234 @@ +"""Source-only admission primitive; never authorizes or dispatches native work. + +Trusted owner mediation must validate claim/PDP/consume before transitions. +One approval admits one operation. A persisted reservation cannot be resumed. +The process lock is held across the whole owner invocation, including cleanup. +""" +from __future__ import annotations + +import fcntl +import os +import re +import sqlite3 +import stat +import uuid +from contextlib import contextmanager +from dataclasses import dataclass +from pathlib import Path + + +class Refused(Exception): + pass + + +@dataclass(frozen=True) +class Binding: + approval_id: str + request_digest: str + operation_id: str + plan_digest: str + + def validate(self): + if any(type(v) is not str for v in (self.approval_id, self.request_digest, self.operation_id, self.plan_digest)): + raise Refused("binding fields must be strings") + if not re.fullmatch(r"[A-Za-z0-9][A-Za-z0-9_-]{0,127}", self.approval_id): + raise Refused("invalid approval identifier") + for digest in (self.request_digest, self.plan_digest): + if not re.fullmatch(r"[0-9a-f]{64}", digest): + raise Refused("invalid digest") + try: + if str(uuid.UUID(self.operation_id)) != self.operation_id: + raise ValueError() + except (ValueError, AttributeError): + raise Refused("invalid operation identifier") from None + + +_NEXT = { + "reserved": {"consume-confirmed", "failed", "unknown"}, + "consume-confirmed": {"authenticating", "failed", "unknown"}, + "authenticating": {"grant-issuing", "failed", "unknown"}, + "grant-issuing": {"grant-issued", "failed", "unknown"}, + "grant-issued": {"applying", "failed", "unknown"}, + "applying": {"readback", "failed", "unknown"}, + "readback": {"verified", "failed", "unknown"}, + "verified": {"cleanup-confirmed", "unknown"}, +} + + +class Journal: + def __init__(self, directory: Path): + # Require an existing owner-private directory: deployment creates it. + if directory.is_symlink() or directory.resolve() != directory.absolute(): + raise Refused("journal path is indirect") + self.directory = directory + self._private(directory.stat(), directory=True) + self._lock_fd = self._open("execution.lock") + try: + fd = self._open("journal.sqlite") + except BaseException: + os.close(self._lock_fd) + del self._lock_fd + raise + original = os.fstat(fd) + os.close(fd) + self.db = sqlite3.connect(directory / "journal.sqlite", isolation_level=None) + current = (directory / "journal.sqlite").stat() + if (original.st_dev, original.st_ino) != (current.st_dev, current.st_ino): + self.close() + raise Refused("journal changed during open") + self.db.execute("PRAGMA synchronous=FULL") + self.db.execute("PRAGMA journal_mode=DELETE") + self.db.execute("CREATE TABLE IF NOT EXISTS operations (approval TEXT PRIMARY KEY, request TEXT NOT NULL, operation TEXT UNIQUE NOT NULL, plan TEXT NOT NULL, state TEXT NOT NULL, evidence TEXT)") + self.db.execute("CREATE TABLE IF NOT EXISTS calls (operation TEXT NOT NULL, ordinal INTEGER NOT NULL, call_digest TEXT NOT NULL, outcome TEXT NOT NULL, evidence TEXT, PRIMARY KEY(operation,ordinal))") + self._held = False + self._admission = None + self._sync_directory() + + @staticmethod + def _private(s, directory=False): + kind = stat.S_ISDIR(s.st_mode) if directory else stat.S_ISREG(s.st_mode) + if not kind or s.st_uid != os.getuid() or s.st_mode & 0o077: + raise Refused("journal is not owner private") + if not directory and s.st_nlink != 1: + raise Refused("journal file has multiple links") + + def _open(self, name): + fd = os.open(self.directory / name, os.O_CREAT | os.O_RDWR | os.O_NOFOLLOW, 0o600) + try: + self._private(os.fstat(fd)) + except BaseException: + os.close(fd) + raise + return fd + + def _sync_directory(self): + fd = os.open(self.directory, os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW) + try: + os.fsync(fd) + finally: + os.close(fd) + + @contextmanager + def locked(self): + if self._held: + raise Refused("nested journal admission") + try: + fcntl.flock(self._lock_fd, fcntl.LOCK_EX | fcntl.LOCK_NB) + except BlockingIOError: + raise Refused("owner invocation already active") from None + self._held = True + try: + yield self + finally: + self._admission = None + self._held = False + fcntl.flock(self._lock_fd, fcntl.LOCK_UN) + + def reserve(self, binding: Binding): + binding.validate() + if not self._held or self._admission is not None: + raise Refused("reservation requires fresh exclusive invocation") + try: + self.db.execute("BEGIN IMMEDIATE") + self.db.execute("INSERT INTO operations VALUES (?,?,?,?,?,NULL)", + (binding.approval_id, binding.request_digest, + binding.operation_id, binding.plan_digest, "reserved")) + self.db.execute("COMMIT") + self._sync_directory() + except sqlite3.IntegrityError: + self.db.execute("ROLLBACK") + raise Refused("approval or operation already admitted") from None + except BaseException: + if self.db.in_transaction: + self.db.execute("ROLLBACK") + raise + self._admission = binding + + def transition(self, binding: Binding, expected: str, target: str, evidence_digest=None): + if not self._held or self._admission != binding: + raise Refused("no live admission") + if target not in _NEXT.get(expected, set()): + raise Refused("invalid state transition") + if target == "cleanup-confirmed" and evidence_digest is None: + raise Refused("cleanup requires evidence") + if evidence_digest is not None and not re.fullmatch(r"[0-9a-f]{64}", evidence_digest): + raise Refused("invalid evidence digest") + try: + self.db.execute("BEGIN IMMEDIATE") + pending=self.db.execute("SELECT COUNT(*) FROM calls WHERE operation=? AND outcome='pending'",(binding.operation_id,)).fetchone()[0] + if pending and target != 'unknown': + raise Refused("unconfirmed external call requires unknown") + changed = self.db.execute( + "UPDATE operations SET state=?, evidence=? WHERE approval=? AND request=? AND operation=? AND plan=? AND state=?", + (target, evidence_digest, binding.approval_id, binding.request_digest, + binding.operation_id, binding.plan_digest, expected)).rowcount + if changed != 1: + raise Refused("journal state changed") + self.db.execute("COMMIT") + self._sync_directory() + except BaseException: + if self.db.in_transaction: + self.db.execute("ROLLBACK") + raise + + def observe(self, binding: Binding): + binding.validate() + row = self.db.execute("SELECT request,operation,plan,state,evidence FROM operations WHERE approval=?", (binding.approval_id,)).fetchone() + if row is None: + return None + if row[:3] != (binding.request_digest, binding.operation_id, binding.plan_digest): + raise Refused("journal binding mismatch") + # Readback cannot create a live admission, even for an interrupted state. + pending = self.db.execute("SELECT COUNT(*) FROM calls WHERE operation=? AND outcome='pending'", (binding.operation_id,)).fetchone()[0] + return {"state": row[3], "evidence_digest": row[4], "dispatch_allowed": False, + "external_outcome_unknown": bool(pending)} + + def before_call(self, binding: Binding, ordinal: int, call_digest: str): + """Persist one exact plan-call intent before the mediator issues it. + + Caller must derive ordinal/digest from the independently pinned owner plan. + This primitive doesn't validate method/body or decide whether a call is allowed. + """ + if not self._held or self._admission != binding: + raise Refused("no live admission") + if type(ordinal) is not int or ordinal < 0 or ordinal > 63: + raise Refused("invalid fixed-plan ordinal") + if type(call_digest) is not str or not re.fullmatch(r"[0-9a-f]{64}", call_digest): + raise Refused("invalid call digest") + try: + self.db.execute("BEGIN IMMEDIATE") + count,pending = self.db.execute("SELECT COUNT(*), COALESCE(SUM(outcome='pending'),0) FROM calls WHERE operation=?",(binding.operation_id,)).fetchone() + state=self.db.execute("SELECT state FROM operations WHERE operation=?",(binding.operation_id,)).fetchone()[0] + if ordinal != count or pending or state in {'failed','unknown','cleanup-confirmed'}: + raise Refused("call is replayed, uncertain or terminal") + self.db.execute("INSERT INTO calls VALUES (?,?,?,'pending',NULL)",(binding.operation_id,ordinal,call_digest)) + self.db.execute("COMMIT") + self._sync_directory() + except BaseException: + if self.db.in_transaction: self.db.execute("ROLLBACK") + raise + + def after_call(self, binding: Binding, ordinal: int, call_digest: str, evidence_digest: str): + if not self._held or self._admission != binding: + raise Refused("no live admission") + if type(ordinal) is not int or ordinal < 0 or ordinal > 63: + raise Refused("invalid fixed-plan ordinal") + if type(call_digest) is not str or not re.fullmatch(r"[0-9a-f]{64}", call_digest): + raise Refused("invalid call digest") + if type(evidence_digest) is not str or not re.fullmatch(r"[0-9a-f]{64}", evidence_digest): + raise Refused("invalid evidence digest") + try: + self.db.execute("BEGIN IMMEDIATE") + n=self.db.execute("UPDATE calls SET outcome='complete', evidence=? WHERE operation=? AND ordinal=? AND call_digest=? AND outcome='pending'",(evidence_digest,binding.operation_id,ordinal,call_digest)).rowcount + if n != 1: raise Refused("call confirmation mismatch") + self.db.execute("COMMIT") + self._sync_directory() + except BaseException: + if self.db.in_transaction: self.db.execute("ROLLBACK") + raise + + def close(self): + if hasattr(self, "db"): + self.db.close() + if hasattr(self, "_lock_fd"): + os.close(self._lock_fd) diff --git a/tests/test_task_execution_journal.py b/tests/test_task_execution_journal.py new file mode 100644 index 0000000..18318a1 --- /dev/null +++ b/tests/test_task_execution_journal.py @@ -0,0 +1,168 @@ +import importlib.util +import multiprocessing +import os +import sys +import tempfile +import unittest +import uuid +from pathlib import Path + +spec = importlib.util.spec_from_file_location('task_execution_journal', Path(__file__).resolve().parents[1] / 'scripts/task_execution_journal.py') +module = importlib.util.module_from_spec(spec) +sys.modules[spec.name] = module +spec.loader.exec_module(module) +Binding, Journal, Refused = module.Binding, module.Journal, module.Refused + + +def reserve_worker(directory, binding, gate, results): + journal = Journal(Path(directory)) + gate.wait() + try: + with journal.locked(): + journal.reserve(binding) + results.put('admitted') + except Refused: + results.put('refused') + finally: + journal.close() + + +class Tests(unittest.TestCase): + def setUp(self): + self.tmp = tempfile.TemporaryDirectory() + self.addCleanup(self.tmp.cleanup) + self.path = Path(self.tmp.name) + self.binding = Binding('approval-1', 'a'*64, str(uuid.uuid4()), 'b'*64) + self.journal = Journal(self.path) + self.addCleanup(self.journal.close) + + def test_actual_multi_process_race_admits_once(self): + context = multiprocessing.get_context('fork') + gate, results = context.Event(), context.Queue() + workers = [context.Process(target=reserve_worker,args=(str(self.path),self.binding,gate,results)) for _ in range(4)] + for w in workers: w.start() + gate.set() + for w in workers: + w.join(10) + if w.is_alive(): w.terminate(); w.join(); self.fail('worker exceeded bound') + self.assertEqual(w.exitcode, 0) + self.assertEqual(sorted(results.get(timeout=2) for _ in workers), ['admitted','refused','refused','refused']) + + def test_reservation_persists_after_process_abandonment(self): + with self.journal.locked(): self.journal.reserve(self.binding) + reopened = Journal(self.path) + try: + self.assertEqual(reopened.observe(self.binding)['state'], 'reserved') + self.assertFalse(reopened.observe(self.binding)['dispatch_allowed']) + with reopened.locked(): + with self.assertRaises(Refused): reopened.reserve(self.binding) + with self.assertRaises(Refused): reopened.transition(self.binding,'reserved','consume-confirmed') + finally: reopened.close() + + def test_same_approval_different_digest_refused(self): + with self.journal.locked(): self.journal.reserve(self.binding) + changed = Binding('approval-1','c'*64,str(uuid.uuid4()),'b'*64) + with self.journal.locked(): + with self.assertRaises(Refused): self.journal.reserve(changed) + with self.assertRaises(Refused): self.journal.observe(changed) + + def test_same_operation_different_approval_refused(self): + with self.journal.locked(): self.journal.reserve(self.binding) + with self.journal.locked(): + with self.assertRaises(Refused): self.journal.reserve(Binding('approval-2','a'*64,self.binding.operation_id,'b'*64)) + + def test_full_path_cleanup_and_terminal_replay(self): + states=['reserved','consume-confirmed','authenticating','grant-issuing','grant-issued','applying','readback','verified','cleanup-confirmed'] + with self.journal.locked(): + self.journal.reserve(self.binding) + for before,after in zip(states,states[1:]): + self.journal.transition(self.binding,before,after,'c'*64) + with self.assertRaises(Refused): self.journal.transition(self.binding,'cleanup-confirmed','applying') + self.assertEqual(self.journal.observe(self.binding),{'state':'cleanup-confirmed','evidence_digest':'c'*64,'dispatch_allowed':False,'external_outcome_unknown':False}) + with self.journal.locked(): + with self.assertRaises(Refused): self.journal.reserve(self.binding) + + def test_unknown_is_terminal(self): + with self.journal.locked(): + self.journal.reserve(self.binding) + self.journal.transition(self.binding,'reserved','unknown') + with self.assertRaises(Refused): self.journal.transition(self.binding,'unknown','reserved') + + def test_early_dispatch_wrong_state_and_cleanup_without_evidence_refused(self): + with self.journal.locked(): + self.journal.reserve(self.binding) + with self.assertRaises(Refused): self.journal.transition(self.binding,'reserved','applying') + with self.assertRaises(Refused): self.journal.transition(self.binding,'consume-confirmed','authenticating') + self.assertEqual(self.journal.observe(self.binding)['state'],'reserved') + + def test_other_live_invocation_cannot_obtain_lock(self): + second=Journal(self.path) + try: + with self.journal.locked(): + with self.assertRaises(Refused): + with second.locked(): pass + finally: second.close() + + def test_symlink_and_hardlink_files_refused(self): + for name,link in [('journal.sqlite','hard'),('execution.lock','symbolic')]: + with tempfile.TemporaryDirectory() as d: + p=Path(d); target=p/'other'; target.touch(mode=0o600) + if link=='hard': os.link(target,p/name) + else: (p/name).symlink_to(target) + with self.assertRaises((Refused,OSError)): Journal(p) + + def test_nonprivate_directory_refused(self): + with tempfile.TemporaryDirectory() as d: + os.chmod(d,0o755) + with self.assertRaises(Refused): Journal(Path(d)) + + def test_binding_rejects_unbounded_or_malformed_metadata(self): + for value in ['token'+ 'x'*200, '../approval', 'approval\n1']: + with self.assertRaises(Refused): Binding(value,'a'*64,self.binding.operation_id,'b'*64).validate() + for value in ['a'*63,'A'*64,'not-a-digest']: + with self.assertRaises(Refused): Binding('a',value,self.binding.operation_id,'b'*64).validate() + + def test_pending_external_call_blocks_next_and_survives_reopen(self): + with self.journal.locked(): + self.journal.reserve(self.binding) + self.journal.before_call(self.binding,0,'d'*64) + with self.assertRaises(Refused): self.journal.before_call(self.binding,1,'e'*64) + with self.assertRaises(Refused): self.journal.transition(self.binding,'reserved','consume-confirmed') + reopened=Journal(self.path) + try: + self.assertTrue(reopened.observe(self.binding)['external_outcome_unknown']) + self.assertFalse(reopened.observe(self.binding)['dispatch_allowed']) + finally: reopened.close() + + def test_call_order_and_exact_confirmation(self): + with self.journal.locked(): + self.journal.reserve(self.binding) + with self.assertRaises(Refused): self.journal.before_call(self.binding,1,'d'*64) + self.journal.before_call(self.binding,0,'d'*64) + with self.assertRaises(Refused): self.journal.after_call(self.binding,0,'e'*64,'f'*64) + self.journal.after_call(self.binding,0,'d'*64,'f'*64) + with self.assertRaises(Refused): self.journal.after_call(self.binding,0,'d'*64,'f'*64) + with self.assertRaises(Refused): self.journal.before_call(self.binding,0,'d'*64) + self.journal.before_call(self.binding,1,'e'*64) + + def test_nonstring_binding_and_boolean_ordinal_refused(self): + with self.assertRaises(Refused): Binding(True,'a'*64,self.binding.operation_id,'b'*64).validate() + with self.journal.locked(): + self.journal.reserve(self.binding) + with self.assertRaises(Refused): self.journal.before_call(self.binding,False,'d'*64) + + def test_confirmation_rejects_sqlite_ordinal_coercion(self): + with self.journal.locked(): + self.journal.reserve(self.binding) + self.journal.before_call(self.binding,0,'d'*64) + for ordinal in (False,0.0,'0',None,-1,64): + with self.subTest(ordinal=ordinal): + with self.assertRaises(Refused): self.journal.after_call(self.binding,ordinal,'d'*64,'f'*64) + self.assertTrue(self.journal.observe(self.binding)['external_outcome_unknown']) + for digest in (None,False,'D'*64,'d'*63): + with self.assertRaises(Refused): self.journal.after_call(self.binding,0,digest,'f'*64) + self.assertTrue(self.journal.observe(self.binding)['external_outcome_unknown']) + self.journal.after_call(self.binding,0,'d'*64,'f'*64) + self.assertFalse(self.journal.observe(self.binding)['external_outcome_unknown']) + +if __name__=='__main__': unittest.main() diff --git a/workplans/RPF-WP-0035-credential-lane-implementation.md b/workplans/RPF-WP-0035-credential-lane-implementation.md index bdfc6c5..d3bb5bb 100644 --- a/workplans/RPF-WP-0035-credential-lane-implementation.md +++ b/workplans/RPF-WP-0035-credential-lane-implementation.md @@ -990,6 +990,7 @@ none of the ordinary generic lifecycle outcomes. id: RPF-WP-0035-T13 status: done priority: high +state_hub_task_id: "8f6966fa-6e9a-58b2-8b40-c47340ec19d1" ``` 2026-10-11: Platform agent loaded its owner instructions/INTENT and RPF35-T02, @@ -1023,3 +1024,57 @@ before the formal v5 exact source review. V4 changes-requested review and earlie failed history remain retained, with no native success, inherited grant or scope promotion. Actual private producer admission, fresh installed role/leeway/policy observation, authenticated founder window and native refusal/cleanup remain gates. + + +2026-10-11 T11 journal preparation refinement (source-only): independently +inspected frozen root-maker v2 manifest +`341cac1de945d2fbe8f516119909bd44fc37e85dccfb38b451981d4de2d402e7`, +verified all input hashes, and ran14 supplied tests plus5 independent checks. +The actual four-process race admits once; a separately forked process exiting +immediately after pending intent leaves durable unknown/nonresumable state. +Private SQLite modes, lock admission and binding/replay protections remain guarded. +Three independent counterexamples show after_call accepts False,0.0 or text'0' +as persisted integer ordinal0, contrary to before_call's exact integer validation. +Completed preparation under this existing done ownerT11 record precedes formal +review; require identical ordinal/call-digest validation before confirmation so +malformed calls cannot clear pending outcome. RPF35-T12 retains caller/PDP/consume +validation, exact body compiler/adapter and owner-private cleanup/recovery after +unknown; this unintegrated primitive proves none of those or full contract/native +acceptance. Inputs/prior reviews are preserved; no privileged/native action occurred. + + +2026-10-11 T11 journal v3 correction preparation (same trial): frozen manifest +`905ff6666d05df6a19d165a535579d917d7de31a43e066c2afc34a57e8cbdc9d` +verified against every file. Strict after_call integer0..63 and64hex string digest +validation now precedes SQLite confirmation; False,0.0 or text'0' cannot clear +pending external outcome.15 supplied tests plus5 independent regressions pass, +including realfork abrupt exit after durable intent and privatefile checks. +This existing completed ownerT11 refinement precedes the formal corrected-source +review. Prior v2 refusal is retained; no extra success/authority trial is counted. +Acceptance is only unintegrated journal source. Actual caller/PDP/consume validation, +independently compiled body/ordinal plan, restricted adapter, owner-private unknown +cleanup recovery and native/whole-contract adoption remain live RPF35-T12 gates. + + +2026-10-11 T13 node-route source preparation refinement (same trial): exact +successor manifest `23a972abc5175e121e594726d2b7f7a28c62109253f58f12623eaf2e5564a035` +verified against all entries. Platform Service openbao-ui-gateway8080 and its +nginx /v1 proxy agree with the proposed bounded founder-held node port-forward; +workstation tunnel/DNS assumptions are not reused as node evidence.54 supplied +lifecycle/route checks plus6 independent public-health/abort checks pass, offline. +Initial execute/recovery health pin and repeated pre-create check fail before +native/Secret effects; public-preflight reads neither stdin nor Kubernetes. +Completed ownT13 preparation precedes this fresh exact source review, not reuse +of v5 acknowledgment. Main execute currently reads private stdin before execute's +health gate; the packet's pre-token-input phrase is not accepted. Private producer +handoff must preserve actual ordering or move the health gate before credential +input when implemented. Public cluster digest detects drift, not authenticated +estate identity. No route was opened or observed; no source packet authenticates +a founder approval. Native role/plugin version and raw/effective expiration, +clock-skew and not-before leeways require actual owner observation/semantic proof. +Issuer readiness_state/Argo ownership is not established by the inspected source; +unmapped means production-tier. If adopted/production-approved, temporary direct +CAS requires an explicit reviewed one-use maintenance exception and close-down +entry, plus reconciliation, before native go. No helper/source acknowledgment +waives that gate. Private token producer/callback/client/custody admission and +actual native negative/revoke/restoration/cleanup remain prerequisites.