diff --git a/docs/assessments/cust81-private-reader/phase-b-r1/apps-owner-phase-b-review.md b/docs/assessments/cust81-private-reader/phase-b-r1/apps-owner-phase-b-review.md new file mode 100644 index 0000000..bb0ae37 --- /dev/null +++ b/docs/assessments/cust81-private-reader/phase-b-r1/apps-owner-phase-b-review.md @@ -0,0 +1,53 @@ +# Apps phase B delivery preparation review + +Disposition: `approved` for exact bounded preparation only. No founder credential, +source-activation or production rollout authorization is inferred. Own workitem +RAPPS-WP-0017-T03; INTENT basis is release contracts, explicit S3 handoffs, +repeatable recovery and evidence before confidence. + +Full ExternalSecret server dry-run accepted and client diff verified only the +single new reader item plus native remoteRef defaults. Both old fields, existing +store, target and all other source spec/metadata are unchanged. The first strict +live equality check correctly refused on native ESO defaults, with no apply; +subsequent projection explicitly verified those defaults. The approved source +replacement is distinct from the current active file and must replace it only +after consent, then pass normal owner source publication before live apply. +Server acceptance does not prove the dedicated KV field or ESO read policy exists. + +Phase B must follow verified phase A *and* terminal verified platform provisioning +under the exact approved CCR. Verify current API pod ready, spec image index and +imageID against published OCI index or its linux/amd64 child (exclude attestation +manifest), source federation/private verification module hashes and exact14 URL +allowlist. Confirm ESO Ready and selected reader-key presence only, then controlled +restart with fresh headroom/PVC readiness and capture-only output. No token or env +value enters argv, source, receipts or logs. + +The native proof wrapper consumes only three exact-byte non-secret packets via +stdin, verifies their compiled hashes and module/source hashes, verifies the +complete14 URL allowlist, and invokes the application's native fetch path without +cache. Temporary packet files are0600 and removed. Four local refusal fixtures +passed; no real credentials or network requests were used. Its output must be +combined with separately verified API pod UID/readiness/image metadata; a +process receipt alone does not prove the target pod identity. Any missing, +mis-hashed, non-exact scope or native fetch outcome refuses success. Native +proof requires all7 sources and14 metadata fetches before registrations/final70. + +Rollback ordering is explicit: revoke dedicated Forgejo PAT and verify; restore +source-controlled two-field ESO mapping to stop rematerialization; remove only +the materialized reader key through a captured exact JSON patch; restart the +current hardened deployment and verify reader absence in new pod/materialized +Secret plus issuer revocation. Only then may an independently approved rollback +to vulnerable Helm revision10 occur. No old-token fallback, default DB restore, +credential re-mint or Secret/env dump is proposed. + +All exact predecessor/replacement digests, SSH delivery/restart/removal commands, +proof hashes/packet paths and gate schema are in phase-b-execution-proposal-r1.json. +No credential creation, ESO apply, Secret mutation, restart or deploy was executed. + +Revision2 of the same proposal corrects malformed shell quoting in the original +reader-removal command. Original proposal/review/manifest remain archived. +The replacement is structured SSH argv with `shlex.join` over exact remote +kubectl argv and compact JSON patch. Offline shell parsing roundtrips exactly +one removal operation at `/data/REUSE_SURFACE_FORGEJO_SOURCE_READ_TOKEN`; no +other key is touched. This refinement is not another successful trial. +Disposition remains approved preparation only, never founder live authority. diff --git a/docs/assessments/cust81-private-reader/phase-b-r1/command-parser-check-r2.json b/docs/assessments/cust81-private-reader/phase-b-r1/command-parser-check-r2.json new file mode 100644 index 0000000..54dfab4 --- /dev/null +++ b/docs/assessments/cust81-private-reader/phase-b-r1/command-parser-check-r2.json @@ -0,0 +1,13 @@ +{ + "id": "CUST81-PHASE-B-COMMAND-PARSER-CHECK-R2", + "status": "passed", + "proposal_revision": 2, + "original_proposal_sha256": "sha256:572af68fcf56072c1fd846101a76611885acd6efedfe5dba10d96d9f77f701e0", + "ssh_argv_count": 3, + "remote_argv_roundtrip": true, + "patch_operation_count": 1, + "patch_op": "remove", + "patch_path": "/data/REUSE_SURFACE_FORGEJO_SOURCE_READ_TOKEN", + "other_field_changes": false, + "live_command_executed": false +} diff --git a/docs/assessments/cust81-private-reader/phase-b-r1/eso-preflight-r1.json b/docs/assessments/cust81-private-reader/phase-b-r1/eso-preflight-r1.json new file mode 100644 index 0000000..db58a9d --- /dev/null +++ b/docs/assessments/cust81-private-reader/phase-b-r1/eso-preflight-r1.json @@ -0,0 +1,31 @@ +{ + "id": "CUST81-APPS-PHASE-B-ESO-PREFLIGHT-R1", + "checked_at": "2026-10-14T23:55:29.993576+00:00", + "target_node_ip": "92.205.62.239", + "status": "verified_preparation", + "active_predecessor_path": "/home/worsch/railiance-apps/manifests/reuse-surface-runtime-externalsecret.yaml", + "active_predecessor_sha256": "e036084aec9fad3bea63cc0d591c3b40a392ab9f54d9226a2d2b3fd7194d8a47", + "proposed_replacement_path": "/home/worsch/railiance-apps/docs/assessments/cust81-private-reader/reuse-surface-runtime-externalsecret.r1.yaml", + "proposed_replacement_sha256": "adfb34c0ee4d01bc602f57cd2320f1658465fb8f8660978828fffa05a5b604b5", + "old_two_fields_retained": true, + "existing_store_unchanged": true, + "live_spec_projected_matches_predecessor": true, + "native_remoteRef_defaults_verified": true, + "previous_attempt": "full live data equality assertion refused on native ESO defaults; no command apply executed, original refusal retained", + "results": [ + { + "operation": "server_dry_run", + "exit_code": 0, + "raw_stdout_stderr_discarded": true + }, + { + "operation": "client_diff", + "exit_code": 1, + "exact_new_reader_item_plus_native_defaults_only": true, + "raw_values_annotations_stderr_discarded": true + } + ], + "credentials_provisioned": false, + "live_apply_performed": false, + "limitation": "server acceptance does not prove dedicated KV field exists or ESO consumer policy reader path granted" +} diff --git a/docs/assessments/cust81-private-reader/phase-b-r1/manifest.json b/docs/assessments/cust81-private-reader/phase-b-r1/manifest.json new file mode 100644 index 0000000..3cbd15d --- /dev/null +++ b/docs/assessments/cust81-private-reader/phase-b-r1/manifest.json @@ -0,0 +1,18 @@ +{ + "proposal_id": "CUST81-APPS-PHASE-B-EXECUTION-PROPOSAL-R1", + "revision": 2, + "owner": "railiance-apps", + "disposition": "approved", + "approved_scope": "bounded source preparation only; no active ESO or live action", + "founder_live_approval": false, + "refinement_or_rescue": true, + "files": { + "apps-owner-phase-b-review.md": "sha256:496c842f4a284d6b2904c027dfd1e8aab85567f19fa74a228f27c4cc578ce026", + "command-parser-check-r2.json": "sha256:5080bdd2ece186200aec1a37b4450c99a50d435444f0f850277b82252516d6e1", + "eso-preflight-r1.json": "sha256:e39f07427af80fd036e6eec21202efe194fff2db67b8523bb07052e1388d8fab", + "native-proof-wrapper-local-checks-r1.json": "sha256:c5fcee128f7b4653ecfc0c455aab57a7efa8f6a9de382af69d447d8065091bab", + "native_runtime_proof_stdin.py": "sha256:1edc317e8563a120b62a6830eebb2875c144b45c57a491eb7da849095c5d1933", + "phase-b-execution-proposal-r1.json": "sha256:13f19158e09b0693a64ff400ecbc3e5ec09d28673731e87733d1e2fad9bd3222", + "run_eso_preflight.py": "sha256:fd42789518e9a6c1305fc3828bf1afb8c9a4e8238b4eeed30f7e7ec05656f09b" + } +} diff --git a/docs/assessments/cust81-private-reader/phase-b-r1/native-proof-wrapper-local-checks-r1.json b/docs/assessments/cust81-private-reader/phase-b-r1/native-proof-wrapper-local-checks-r1.json new file mode 100644 index 0000000..43cd703 --- /dev/null +++ b/docs/assessments/cust81-private-reader/phase-b-r1/native-proof-wrapper-local-checks-r1.json @@ -0,0 +1,15 @@ +{ + "id": "CUST81-NATIVE-RUNTIME-PROOF-PREPARATION-CHECKS-R1", + "status": "passed", + "wrapper_sha256": "1edc317e8563a120b62a6830eebb2875c144b45c57a491eb7da849095c5d1933", + "fixture_cases": [ + "missing_reader", + "malformed_allowlist", + "tampered_packet", + "native_refusal" + ], + "native_network_requests": 0, + "real_credentials_used": false, + "failure_output_sentinel_excluded": true, + "scope_refusal_before_any_fetch": true +} diff --git a/docs/assessments/cust81-private-reader/phase-b-r1/native_runtime_proof_stdin.py b/docs/assessments/cust81-private-reader/phase-b-r1/native_runtime_proof_stdin.py new file mode 100644 index 0000000..8b76d09 --- /dev/null +++ b/docs/assessments/cust81-private-reader/phase-b-r1/native_runtime_proof_stdin.py @@ -0,0 +1,38 @@ +"""Approved preparation only: execute in verified hardened API pod after phase B. +stdin envelope contains only three base64-encoded hash-bound non-secret packets. +No token accepted; native module consumes its reviewed runtime source credential. +""" +import base64,hashlib,json,os,tempfile +from pathlib import Path +import sys +from reuse_surface import federation, private_source_verify as native +EXPECTED={'proposal':'7819eb51d249f5c7aff4df9fb520afcfb76603b05a4104439499102b6c20af99','disclosure':'46ac4fe49a08054cc215aade2fbaf3b36ee334520997857ed84f530b52da9d35','consent':'4a4602ad926e3af855d6ddba4731430d33e4a7432c507ba0a5193b9f43056b52'} +FEDI='dbaa40f25cc0f090143578cd1c7068cb2cb00960fafd17d5239bf8a5bac514dd' +NATIVE='c67a284091cc4dd62dca56658a14b8ea1357e2b3df1518120da4c51e0ee8d85c' +receipt={'id':'CUST81-NATIVE-RUNTIME-PROOF-R1','status':'unverified','raw_errors_or_values_emitted':False} +try: + source_sha=hashlib.sha256(Path(federation.__file__).read_bytes()).hexdigest() + helper_sha=hashlib.sha256(Path(native.__file__).read_bytes()).hexdigest() + assert source_sha==FEDI and helper_sha==NATIVE + envelope=json.loads(sys.stdin.buffer.read(1048576)) + assert set(envelope)==set(EXPECTED) + with tempfile.TemporaryDirectory(prefix='cust81-native-packets-') as temporary: + paths={} + for name,digest in EXPECTED.items(): + content=base64.b64decode(envelope[name],validate=True) + assert hashlib.sha256(content).hexdigest()==digest + p=Path(temporary)/(name+'.json');p.write_bytes(content);p.chmod(0o600);paths[name]=p + sources=list(native._prepared_sources(paths['proposal'],paths['disclosure'],paths['consent'])) + expected_urls={native._raw_url(source['repo'],source['consented_commit'],path) for source,files in sources for path in files} + allow=json.loads(os.environ.get('REUSE_SURFACE_AUTH_SOURCE_ALLOWLIST','{}')) + assert set(allow)=={native.AUTH_ENV} and len(allow[native.AUTH_ENV])==14 and set(allow[native.AUTH_ENV])==expected_urls + # Presence only: never print/read the secret value here. Native acquisition + # is subsequently performed only at its reviewed exact URL routing boundary. + key_present=native.AUTH_ENV in os.environ + assert key_present + result=native.verify(paths['proposal'],paths['disclosure'],paths['consent']) + receipt.update(source_sha256=source_sha,helper_sha256=helper_sha,packet_sha256=EXPECTED,runtime_allowlist_exact14=True,reader_key_present=True,native_fetch=result,status='verified' if result['all_verified'] else 'native_fetch_failed') +except Exception: + receipt.update(status='runtime_or_native_proof_refused',error='hash_scope_or_native_validation_failed') +print(json.dumps(receipt,sort_keys=True)) +raise SystemExit(0 if receipt['status']=='verified' else 1) diff --git a/docs/assessments/cust81-private-reader/phase-b-r1/phase-b-execution-proposal-r1.json b/docs/assessments/cust81-private-reader/phase-b-r1/phase-b-execution-proposal-r1.json new file mode 100644 index 0000000..34d390a --- /dev/null +++ b/docs/assessments/cust81-private-reader/phase-b-r1/phase-b-execution-proposal-r1.json @@ -0,0 +1,88 @@ +{ + "id": "CUST81-APPS-PHASE-B-EXECUTION-PROPOSAL-R1", + "disposition": "approved", + "approved_scope": "bounded preparation only; founder live go still required", + "status": "prepared_not_executed", + "workitem": "RAPPS-WP-0017-T03", + "active_predecessor_sha256": "e036084aec9fad3bea63cc0d591c3b40a392ab9f54d9226a2d2b3fd7194d8a47", + "replacement_sha256": "adfb34c0ee4d01bc602f57cd2320f1658465fb8f8660978828fffa05a5b604b5", + "preconditions": [ + "verified phase A current API pod ready pinned hardened image/source hashes", + "platform provisioner terminal verified and approved CCR revision executed", + "Forgejo exact7 readonly grants and PAT receipt verified", + "native ESO path-read policy/store issuer receipt verified", + "founder consent to exact phase B source update and delivery" + ], + "source_update_after_consent": { + "command": "cp docs/assessments/cust81-private-reader/reuse-surface-runtime-externalsecret.r1.yaml manifests/reuse-surface-runtime-externalsecret.yaml", + "publication": "owner commits only exact replacement and normal rmgr sync --push; verify primary exact source commit before liveapply", + "not_executed": true + }, + "apply_command": "ssh railiance01 'KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl apply -f /tmp/cust81-phase-b/reuse-surface-runtime-externalsecret.yaml'", + "sync_verify_before_restart": "wait for ESO Ready and selected reader-key-presence boolean via reviewed captured-output wrapper; never raw Secret/annotation/env output", + "restart_command": "ssh railiance01 'KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl rollout restart deployment/reuse-surface --namespace reuse'", + "restart_wait_command": "ssh railiance01 'KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl rollout status deployment/reuse-surface --namespace reuse --timeout=300s'", + "headroom_gate": "recheck100m/256Mi surge headroom/PVC and actual hardened deployment before restart", + "cleanup_order": [ + "credential owner revokes exact dedicated Forgejo PAT and verifies revocation; no oldtoken fallback", + "restore reviewed two-field ESO manifest through source-controlled owner lane and apply, stops rematerialization", + "remove only REUSE_SURFACE_FORGEJO_SOURCE_READ_TOKEN from reuse/reuse-surface-env with captured-output exact JSON patch", + "restart/wait current hardened deployment, verify reader-key absence boolean in new pod and materialized Secret plus exact token revocation", + "only then may separately approved Helm rollback reuse10 restore vulnerable priorimage; do not restore DB by default" + ], + "raw_output_contract": "all mutating/proof child stdout/stderr captured/discarded; only whitelisted outcome/proof JSON may reach receipts", + "runtime_proof": { + "pod_metadata_schema": [ + "verified API pod name and UID", + "Ready true", + "expected spec image OCI indexsha2364b7e...", + "actual imageID equals index or linux/amd64childsha1a69354af2bc87d4baaecc4b02e13fda468efd3746024f440cc6d138beeee2ab", + "node92.205.62.239", + "source/header-routing/native helper hashes verified", + "exact14 allowlist boolean", + "reader-key presence boolean", + "native14fetch/7consentedhashall_verified" + ], + "wrapper_path": "/tmp/cust81-apps-reader-owner/docs/assessments/cust81-private-reader/phase-b-r1/native_runtime_proof_stdin.py", + "wrapper_sha256": "1edc317e8563a120b62a6830eebb2875c144b45c57a491eb7da849095c5d1933", + "packets": { + "proposal": { + "path": "/home/worsch/the-custodian/docs/assessments/netkingdom-2026-10-14/private-reader-provisioning-preparation-r1.json", + "sha256": "7819eb51d249f5c7aff4df9fb520afcfb76603b05a4104439499102b6c20af99" + }, + "disclosure": { + "path": "/home/worsch/the-custodian/docs/assessments/netkingdom-2026-10-14/private-source-disclosure-proposal-r1.json", + "sha256": "46ac4fe49a08054cc215aade2fbaf3b36ee334520997857ed84f530b52da9d35" + }, + "consent": { + "path": "/home/worsch/the-custodian/docs/assessments/netkingdom-2026-10-14/private-source-owner-consent-r1.json", + "sha256": "4a4602ad926e3af855d6ddba4731430d33e4a7432c507ba0a5193b9f43056b52" + } + }, + "invocation": "capture kubectl --kubeconfig -n reuse exec -i -c reuse-surface -- python3 -c ; stdin JSON envelope {proposal:base64(exactbytes),disclosure:base64(exactbytes),consent:base64(exactbytes)}; no token/credential in argv or stdin; wrapper writes/removes only temporary nonsecret packet files", + "exit_success_required": true + }, + "no_live_credential_or_apply_action": true, + "revision": 2, + "refinement_or_rescue": true, + "original_revision_sha256": "sha256:572af68fcf56072c1fd846101a76611885acd6efedfe5dba10d96d9f77f701e0", + "reader_key_removal_ssh_argv": [ + "ssh", + "railiance01", + "env KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl patch secret reuse-surface-env --namespace reuse --type=json -p '[{\"op\":\"remove\",\"path\":\"/data/REUSE_SURFACE_FORGEJO_SOURCE_READ_TOKEN\"}]'" + ], + "reader_key_removal_remote_argv": [ + "env", + "KUBECONFIG=/etc/rancher/k3s/k3s.yaml", + "kubectl", + "patch", + "secret", + "reuse-surface-env", + "--namespace", + "reuse", + "--type=json", + "-p", + "[{\"op\":\"remove\",\"path\":\"/data/REUSE_SURFACE_FORGEJO_SOURCE_READ_TOKEN\"}]" + ], + "reader_key_removal_offline_check": "passed shell roundtrip exact single remove op on only selected reader key; no other data field/annotation/spec touched" +} diff --git a/docs/assessments/cust81-private-reader/phase-b-r1/run_eso_preflight.py b/docs/assessments/cust81-private-reader/phase-b-r1/run_eso_preflight.py new file mode 100644 index 0000000..a1640b6 --- /dev/null +++ b/docs/assessments/cust81-private-reader/phase-b-r1/run_eso_preflight.py @@ -0,0 +1,30 @@ +from pathlib import Path +import subprocess,json,yaml,hashlib,datetime +art=Path(__file__).resolve().parent +canonical=Path('/home/worsch/railiance-apps') +old=canonical/'manifests/reuse-surface-runtime-externalsecret.yaml';new=canonical/'docs/assessments/cust81-private-reader/reuse-surface-runtime-externalsecret.r1.yaml' +base=yaml.safe_load(old.read_text());proposal=yaml.safe_load(new.read_text()) +assert proposal['spec']['data'][:-1]==base['spec']['data'] +item=proposal['spec']['data'][-1] +assert item=={'secretKey':'REUSE_SURFACE_FORGEJO_SOURCE_READ_TOKEN','remoteRef':{'key':'workloads/reuse/reuse-surface/forgejo-source-read','property':'FORGEJO_SOURCE_TOKEN'}} +assert {k:v for k,v in proposal.items() if k!='spec'}=={k:v for k,v in base.items() if k!='spec'} +assert {k:v for k,v in proposal['spec'].items() if k!='data'}=={k:v for k,v in base['spec'].items() if k!='data'} +kube=['kubectl','--kubeconfig','/home/worsch/.kube/config-railiance01'] +p=subprocess.run(kube+['get','nodes','-o','json'],capture_output=True,timeout=20);nodes=json.loads(p.stdout);assert p.returncode==0 and len(nodes['items'])==1 and any(a['address']=='92.205.62.239' for a in nodes['items'][0]['status']['addresses']) +p=subprocess.run(kube+['-n','reuse','get','externalsecret','reuse-surface-runtime','-o','json'],capture_output=True,timeout=20);assert p.returncode==0;live=json.loads(p.stdout) +rows=[{'secretKey':r['secretKey'],'remoteRef':{k:r['remoteRef'][k] for k in ('key','property')}} for r in live['spec']['data']] +assert rows==base['spec']['data'] and live['spec']['secretStoreRef']==base['spec']['secretStoreRef'] +assert all({k:v for k,v in r['remoteRef'].items() if k not in ('key','property')}=={'conversionStrategy':'Default','decodingStrategy':'None','metadataPolicy':'None'} for r in live['spec']['data']) +results=[] +for args in [['apply','--dry-run=server','-f',str(new)],['diff','-f',str(new)]]: + p=subprocess.run(kube+['-n','reuse']+args,capture_output=True,timeout=60) + if args[0]=='diff': + changed=[line[1:].strip() for line in p.stdout.decode(errors='replace').splitlines() if line.startswith(('+','-')) and not line.startswith(('+++','---'))] + intended={'- remoteRef:', 'key: workloads/reuse/reuse-surface/forgejo-source-read','property: FORGEJO_SOURCE_TOKEN','secretKey: REUSE_SURFACE_FORGEJO_SOURCE_READ_TOKEN','conversionStrategy: Default','decodingStrategy: None','metadataPolicy: None'} + other=[line for line in changed if line not in intended and not line.startswith('generation:')] + assert not other + results.append({'operation':'client_diff','exit_code':p.returncode,'exact_new_reader_item_plus_native_defaults_only':True,'raw_values_annotations_stderr_discarded':True}) + else:results.append({'operation':'server_dry_run','exit_code':p.returncode,'raw_stdout_stderr_discarded':True}) +assert results[0]['exit_code']==0 and results[1]['exit_code'] in (0,1) +r={'id':'CUST81-APPS-PHASE-B-ESO-PREFLIGHT-R1','checked_at':datetime.datetime.now(datetime.timezone.utc).isoformat(),'target_node_ip':'92.205.62.239','status':'verified_preparation','active_predecessor_path':str(old),'active_predecessor_sha256':hashlib.sha256(old.read_bytes()).hexdigest(),'proposed_replacement_path':str(new),'proposed_replacement_sha256':hashlib.sha256(new.read_bytes()).hexdigest(),'old_two_fields_retained':True,'existing_store_unchanged':True,'live_spec_projected_matches_predecessor':True,'native_remoteRef_defaults_verified':True,'previous_attempt':'full live data equality assertion refused on native ESO defaults; no command apply executed, original refusal retained','results':results,'credentials_provisioned':False,'live_apply_performed':False,'limitation':'server acceptance does not prove dedicated KV field exists or ESO consumer policy reader path granted'} +(art/'eso-preflight-r1.json').write_text(json.dumps(r,indent=2)+'\n');print(json.dumps(r,indent=2))