fix(recovery): bind admitted host and record live provider scope approval
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a13eab-1e6a-7b33-9c37-372e90ada3a2
This commit is contained in:
tegwick 2026-10-16 07:44:36 +02:00
parent c31d21ba7d
commit a17aa7edc1
15 changed files with 393 additions and 7 deletions

View file

@ -375,3 +375,37 @@ Find this functionality through the owning registry entry
disaster-recovery, age) federated by reuse-surface, related to
`capability.railiance.bootstrap-sequencing`. Maturity remains D3/A2/C1/R0;
source fixtures and discoverability do not assert live production acceptance.
## Live admission update — 2026-10-16
The operator approved the exact packet in decision
`40bfae40-6108-4e51-8613-073339f5345f`. The first owner login succeeded but
Nextcloud returned publisher permission21 for requested5. Setup refused before
publishing any new KV value. Official Nextcloud link-share normalization adds
permission16 (re-sharing) to read-enabled public links when outgoing federation
is enabled. The operator then explicitly approved folder-only publisher21
(read/create/re-share) and retention25 (read/delete/re-share), recorded in
`5edd5203-fae7-461b-8775-5d22b7873971`. The two CCRs and setup guards now require
that additional explicit approval. Neither credential gains update rights,
other-folder or account administration. New-share metadata and failed-attempt
receipts are retained in the October16 live evidence folder. This supersedes
the initial no-re-sharing provider assumption; it does not infer a native test
pass from approval.
Node preflight also verified that `railiance01` is an SSH alias whose actual
hostname is `239.62.205.92.host.secureserver.net`. Runtime/installer now require
that exact hostname, the reviewed machine-ID hash and the original cluster UID,
plus root. No server hostname or machine identity was changed.52 focused
checks passed including the real synthetic encrypted/native PG fixture after
this guard repair. Unapproved-CCR negative tests use proposed fixtures even
when the actual owner requests have been approved.
Both exact guarded DNS-selector patches passed server-dry-run and were applied.
The node has active k3s with network-policy rules present. The source-bound
runtime release was installed and unit validation completed; both timers remain
disabled. Provider admission/readback and actual full capture remain pending;
no periodic capture/expiry is enabled by installation alone. One subsequent
OIDC attempt timed out before owner-command handoff; it did not run mutations,
and its possible session revocation was unconfirmed. Only the contained owner
login lane is retried, without switching to root or inspecting captured bytes.

View file

@ -0,0 +1,59 @@
{
"schema": "netkingdom.identity-runtime-install.v1",
"status": "prepared_not_installed",
"decision_ref": "40bfae40-6108-4e51-8613-073339f5345f",
"release_id": "bf8b38f185037515cfad9eebcddefc9f60ace724c32e10d89ae8307dc95a4eb7",
"release_directory": "/opt/net-kingdom-backup/releases/bf8b38f185037515cfad9eebcddefc9f60ace724c32e10d89ae8307dc95a4eb7",
"runtime_files": [
{
"path": "tools/bootstrap-recovery/capture-identity.py",
"sha256": "47dca7c4dc96fa7eb9fb02c81fca9ca8dc5281aac918979eb7367148168ba705"
},
{
"path": "tools/bootstrap-recovery/identity-files.py",
"sha256": "d0063a9eedd3610e3d45bd2d834aae83cff74e4b3504d138b3548f427e89331d"
},
{
"path": "tools/bootstrap-recovery/identity-bundle.py",
"sha256": "524a03c065db4307fcde83d33af39503f3de19cb6ef3a8ca72c991d4a8c08ee6"
},
{
"path": "tools/bootstrap-recovery/identity-runtime.py",
"sha256": "97224760f5e21ac9ca1d0d96eeec7427afd7d6eea30a218629a6e409d74fe560"
},
{
"path": "tools/bootstrap-recovery/identity-offsite.py",
"sha256": "e7c31fa9ee081961af873348ee3b4829a645d40c7dc7f1e22c564aa9ed01bc49"
},
{
"path": "tools/bootstrap-recovery/identity-retention.py",
"sha256": "a41ea4759f69c35548149fc8d0d5ace547f16cf9fe4c9dac10b119a4d0becdec"
},
{
"path": "tools/bootstrap-recovery/identity-backup-profile.json",
"sha256": "40f9e5b5bb957e5b23e03b31701702b850502d16a92a0fa0ebf92618cc3f18a1"
},
{
"path": "tools/bootstrap-recovery/prepare-identity-coverage.py",
"sha256": "cd5f3067d28b4c7cc93ed08b8cf3869218bdecf7c54b5dffed22d697de71dbb1"
},
{
"path": "tools/bootstrap-recovery/install-identity-backup.py",
"sha256": "5c612a2a51c9b59aad8cc01d418c2f563cbd92c62dc1fa8be994e5fb59df90f1"
},
{
"path": "sso-mfa/k8s/privacyidea/key-custody-remote.py",
"sha256": "27b2b885c81923d85054e3999c5613e104fe627779b2b50398ed9bed5088f47e"
}
],
"units": {
"net-kingdom-identity-backup.service": "[Unit]\nDescription=Encrypted full identity backup and verified Storage Share readback\nAfter=network-online.target k3s.service\nConditionPathExists=/var/lib/net-kingdom-backup/accepted-recovery.json\n[Service]\nType=oneshot\nUser=root\nGroup=root\nUMask=0077\nStateDirectory=net-kingdom-backup\nStateDirectoryMode=0700\nNoNewPrivileges=true\nPrivateTmp=true\nPrivateDevices=true\nProtectSystem=strict\nProtectHome=true\nReadWritePaths=/var/lib/net-kingdom-backup\nCapabilityBoundingSet=\nRestrictAddressFamilies=AF_UNIX AF_INET AF_INET6\nProtectKernelTunables=true\nProtectKernelModules=true\nProtectControlGroups=true\nMemoryMax=3G\nCPUQuota=200%\nTasksMax=128\nTimeoutStartSec=45min\nTimeoutStopSec=5min\nExecStartPre=/usr/bin/python3 -I /opt/net-kingdom-backup/releases/bf8b38f185037515cfad9eebcddefc9f60ace724c32e10d89ae8307dc95a4eb7/tools/bootstrap-recovery/identity-runtime.py retention --kubeconfig /etc/rancher/k3s/k3s.yaml --state /var/lib/net-kingdom-backup\nExecStart=/usr/bin/python3 -I /opt/net-kingdom-backup/releases/bf8b38f185037515cfad9eebcddefc9f60ace724c32e10d89ae8307dc95a4eb7/tools/bootstrap-recovery/identity-runtime.py scheduled --kubeconfig /etc/rancher/k3s/k3s.yaml --state /var/lib/net-kingdom-backup --decision-id 40bfae40-6108-4e51-8613-073339f5345f\nExecStartPost=/usr/bin/python3 -I /opt/net-kingdom-backup/releases/bf8b38f185037515cfad9eebcddefc9f60ace724c32e10d89ae8307dc95a4eb7/tools/bootstrap-recovery/identity-runtime.py retention --kubeconfig /etc/rancher/k3s/k3s.yaml --state /var/lib/net-kingdom-backup\n",
"net-kingdom-identity-backup.timer": "[Unit]\nDescription=Daily full identity recovery bundle\n[Timer]\nOnCalendar=*-*-* 03:45:00 UTC\nPersistent=true\nRandomizedDelaySec=5min\nUnit=net-kingdom-identity-backup.service\n[Install]\nWantedBy=timers.target\n",
"net-kingdom-identity-backup-health.service": "[Unit]\nDescription=Identity backup age check with durable failure reporting\nAfter=network-online.target k3s.service\n[Service]\nType=oneshot\nUser=root\nGroup=root\nUMask=0077\nStateDirectory=net-kingdom-backup\nStateDirectoryMode=0700\nNoNewPrivileges=true\nPrivateTmp=true\nPrivateDevices=true\nProtectSystem=strict\nProtectHome=true\nReadWritePaths=/var/lib/net-kingdom-backup\nCapabilityBoundingSet=\nRestrictAddressFamilies=AF_UNIX AF_INET AF_INET6\nProtectKernelTunables=true\nProtectKernelModules=true\nProtectControlGroups=true\nMemoryMax=3G\nCPUQuota=200%\nTasksMax=128\nTimeoutStartSec=45min\nTimeoutStopSec=5min\nExecStart=/usr/bin/python3 -I /opt/net-kingdom-backup/releases/bf8b38f185037515cfad9eebcddefc9f60ace724c32e10d89ae8307dc95a4eb7/tools/bootstrap-recovery/identity-runtime.py status --kubeconfig /etc/rancher/k3s/k3s.yaml --state /var/lib/net-kingdom-backup\n",
"net-kingdom-identity-backup-health.timer": "[Unit]\nDescription=Hourly identity backup freshness check\n[Timer]\nOnCalendar=hourly\nPersistent=true\nUnit=net-kingdom-identity-backup-health.service\n[Install]\nWantedBy=timers.target\n"
},
"timers_automatically_enabled": false,
"first_capture_command": "/usr/bin/python3 -I /opt/net-kingdom-backup/releases/bf8b38f185037515cfad9eebcddefc9f60ace724c32e10d89ae8307dc95a4eb7/tools/bootstrap-recovery/identity-runtime.py first-capture --kubeconfig /etc/rancher/k3s/k3s.yaml --state /var/lib/net-kingdom-backup --decision-id 40bfae40-6108-4e51-8613-073339f5345f",
"activation_requires_independent_recovery": true,
"source_contains_credentials": false
}

View file

@ -0,0 +1,27 @@
{
"status": "capture_dns_exclusions_verified",
"attempted": [
{
"namespace": "sso",
"name": "allow-egress-dns",
"uid": "d2a1bd49-7035-437b-9b8e-e9e66b203365"
},
{
"namespace": "mfa",
"name": "allow-egress-dns",
"uid": "1d23ed08-bb6f-4959-b72e-3f03af40f136"
}
],
"verified": [
{
"namespace": "sso",
"name": "allow-egress-dns",
"uid": "d2a1bd49-7035-437b-9b8e-e9e66b203365"
},
{
"namespace": "mfa",
"name": "allow-egress-dns",
"uid": "1d23ed08-bb6f-4959-b72e-3f03af40f136"
}
]
}

View file

@ -0,0 +1,132 @@
{
"schema": "netkingdom.identity-isolation.v1",
"status": "prepared_not_applied",
"kubeconfig": "/home/worsch/.kube/config",
"source_sha256": "88d1e13112a44c79571825af89d3fe5b01fa490cff2653badef4c62a45c844f1",
"policies": [
{
"namespace": "sso",
"name": "allow-egress-dns",
"uid": "d2a1bd49-7035-437b-9b8e-e9e66b203365",
"patch": [
{
"op": "test",
"path": "/metadata/uid",
"value": "d2a1bd49-7035-437b-9b8e-e9e66b203365"
},
{
"op": "test",
"path": "/metadata/resourceVersion",
"value": "3623833"
},
{
"op": "test",
"path": "/spec",
"value": {
"egress": [
{
"ports": [
{
"port": 53,
"protocol": "UDP"
},
{
"port": 53,
"protocol": "TCP"
}
],
"to": [
{
"namespaceSelector": {
"matchLabels": {
"kubernetes.io/metadata.name": "kube-system"
}
}
}
]
}
],
"podSelector": {},
"policyTypes": [
"Egress"
]
}
},
{
"op": "replace",
"path": "/spec/podSelector",
"value": {
"matchExpressions": [
{
"key": "net-kingdom/capture",
"operator": "DoesNotExist"
}
]
}
}
]
},
{
"namespace": "mfa",
"name": "allow-egress-dns",
"uid": "1d23ed08-bb6f-4959-b72e-3f03af40f136",
"patch": [
{
"op": "test",
"path": "/metadata/uid",
"value": "1d23ed08-bb6f-4959-b72e-3f03af40f136"
},
{
"op": "test",
"path": "/metadata/resourceVersion",
"value": "3623822"
},
{
"op": "test",
"path": "/spec",
"value": {
"egress": [
{
"ports": [
{
"port": 53,
"protocol": "UDP"
},
{
"port": 53,
"protocol": "TCP"
}
],
"to": [
{
"namespaceSelector": {
"matchLabels": {
"kubernetes.io/metadata.name": "kube-system"
}
}
}
]
}
],
"podSelector": {},
"policyTypes": [
"Egress"
]
}
},
{
"op": "replace",
"path": "/spec/podSelector",
"value": {
"matchExpressions": [
{
"key": "net-kingdom/capture",
"operator": "DoesNotExist"
}
]
}
}
]
}
]
}

View file

@ -0,0 +1,17 @@
{
"status": "metadata_reviewed",
"shares": [
{
"id": "26",
"share_type": 3,
"permissions": 21,
"path": "/railiance-backups/net-kingdom-identity",
"label": "net-kingdom-identity-publisher",
"item_type": "folder",
"public_upload": null,
"hide_download": 0,
"token_present": true,
"token_shape_valid": true
}
]
}

View file

@ -0,0 +1,15 @@
{
"status": "refused_provider_permission_scope",
"action": "publisher",
"caller_entity_id": "4a1f663c-0621-0483-edd0-f852274f4b6b",
"caller_auth_path": "auth/netkingdom/oidc/callback",
"quota_before": {
"quota_bytes": 10737418240,
"used_bytes": 6978016729,
"available_bytes": 3759401511
},
"folder_created": true,
"share_created": true,
"new_credential_published": false,
"native_delivery_started": false
}

View file

@ -0,0 +1,42 @@
{
"status": "approved_native_provider_delivery_checks_in_progress",
"observed_at": "2026-10-15T23:56:00.293983+00:00",
"approval_decision": "40bfae40-6108-4e51-8613-073339f5345f",
"approved_platform_source_commit": "69a792c",
"first_owner_session": "child_failed_session_revoked",
"second_owner_session": "metadata_review_succeeded_session_revoked",
"new_identity_bundle_created": false,
"identity_job_installed": true,
"new_credentials_published_to_openbao": false,
"existing_backup_changes": false,
"observed_permissions": 21,
"requested_permissions": 5,
"provider_added_permission": 16,
"retention_25_inferred_not_created": true,
"provider_reference": "https://github.com/nextcloud/server/blob/stable31/apps/files_sharing/lib/Controller/ShareAPIController.php#L1011-L1015",
"provider_source_sha256": "f361dcf7138302d72a95148933b2ed7bd69de844dff116a1d2a23c24c0dda53d",
"scope_change_owner_decision_pending": false,
"runtime_host_preflight": {
"ssh_alias": "railiance01",
"hostname": "239.62.205.92.host.secureserver.net",
"machine_id_sha256": "fe7367a60951922122af7ba18ed2cde65c7e0a232bbedfb045cb575de2094c2f",
"sudo_root_verified": true,
"cluster_uid_match": true,
"k3s_active": true,
"free_kib": 126777924
},
"source_repairs": [
"Bind actual runtime host hostname and machine identity rather than SSH alias",
"Keep unapproved-CCR negative tests proposed independently of actual owner approval status"
],
"identity_timers_enabled": false,
"scope_change_owner_decision": "5edd5203-fae7-461b-8775-5d22b7873971",
"approved_provider_masks": {
"publisher": 21,
"retention": 25
},
"focused_tests_passed": 52,
"temporary_dns_selector_exclusions_applied": true,
"network_policy_rule_lines_present": 649,
"installed_runtime_release": "bf8b38f185037515cfad9eebcddefc9f60ace724c32e10d89ae8307dc95a4eb7"
}

View file

@ -208,3 +208,18 @@ def test_full_new_archive_decrypt_extract_native_database_restore_and_cleanup(st
assert r['container_cleanup_verified'] and r['temporary_plaintext_cleanup_verified']
assert not r['full_service_authentication_proven']
finally:subprocess.run(['docker','rm','--force','--volumes',fixture],stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL,timeout=30)
def test_runtime_host_requires_owner_and_exact_machine_binding(monkeypatch):
import hashlib,socket
module=load('identity-bundle')
current=module.profile();current['runtime_host']={'hostname':'verified-node','machine_id_sha256':hashlib.sha256(b'fixture-machine').hexdigest()}
monkeypatch.setattr(module,'profile',lambda:current)
monkeypatch.setattr(module.os,'geteuid',lambda:0);monkeypatch.setattr(socket,'gethostname',lambda:'verified-node')
original=Path.read_bytes
monkeypatch.setattr(Path,'read_bytes',lambda p:b'fixture-machine' if str(p)=='/etc/machine-id' else original(p))
module.require_runtime_host()
monkeypatch.setattr(socket,'gethostname',lambda:'foreign-node')
with pytest.raises(module.Refused):module.require_runtime_host()
monkeypatch.setattr(socket,'gethostname',lambda:'verified-node');monkeypatch.setattr(module.os,'geteuid',lambda:1000)
with pytest.raises(module.Refused):module.require_runtime_host()

View file

@ -113,6 +113,12 @@ def test_missing_independently_recovered_point_refuses_all_expiration():
@pytest.mark.parametrize('action,number',[('publisher',48),('retention',49)])
def test_proposed_ccr_cannot_create_provider_share_or_reader(monkeypatch,action,number):
path=setup.PLATFORM/f'credential-change-requests/CCR-2026-{number:04d}-net-kingdom-backup-{action}.yaml'
from types import SimpleNamespace
import yaml
proposed=yaml.safe_load(path.read_text());proposed['status']='proposed';proposed['review']['comments']=[]
# The negative fixture must stay proposed after the real owner approves a CCR.
original_load=setup.load
monkeypatch.setattr(setup,'load',lambda name,p:SimpleNamespace(validate_ccr=lambda _: (proposed,[],[])) if name=='credential_change' else original_load(name,p))
monkeypatch.setattr(setup.inventory,'caller_credentials',lambda:pytest.fail('unapproved request reached credential read'))
with pytest.raises(setup.Refused):setup.run(action,hashlib.sha256(path.read_bytes()).hexdigest(),{})

View file

@ -136,8 +136,8 @@
"initial": "Storage Share Backup/railiance-backups/net-kingdom-identity/",
"future_secondary": "s3://railiance-platform-pg-backup/platform-pg/application-archives/net-kingdom/; not implemented/admitted in this rollout",
"admitted": false,
"publisher": "CCR-2026-0048: new folder-only read/create public DAV share, delivered by exact ESO reader; no operator password in runtime",
"retention": "CCR-2026-0049: separate folder-only read/delete share and process; newest plus seven daily/two weekly and independently recovered pinned generation; unknown/unindexed points never deleted",
"publisher": "CCR-2026-0048: new folder-only read/create public DAV share, delivered by exact ESO reader; no operator password in runtime; explicitly owner-approved provider-added re-sharing (permissions21)",
"retention": "CCR-2026-0049: separate folder-only read/delete share and process; newest plus seven daily/two weekly and independently recovered pinned generation; unknown/unindexed points never deleted; explicitly owner-approved provider-added re-sharing (permissions25)",
"schedule": "source prepared: daily 03:45 UTC plus up to five minutes jitter, hourly 25-hour freshness check; installation leaves timers disabled until independent archive recovery",
"quota": "512 MiB ceiling, two GiB fresh provider headroom; initial 10 GiB account quota checked; unsupported public-share quota fails closed"
},
@ -149,5 +149,10 @@
"Attended independent age-key proof: wrong-key denial, complete archive hashes, SQLite/RSA checks, disposable native PostgreSQL restore and verified cleanup before timer activation",
"Full NK49 closure separately requires native directory/issuer/MFA authentication, retained token decryption, audit signature continuity, current callers and legacy credential dispositions; archive acceptance does not close those gates",
"Host-local health cannot report a dead host; external outage monitoring and second-provider copy remain separate coverage gaps"
]
],
"runtime_host": {
"ssh_alias": "railiance01",
"hostname": "239.62.205.92.host.secureserver.net",
"machine_id_sha256": "fe7367a60951922122af7ba18ed2cde65c7e0a232bbedfb045cb575de2094c2f"
}
}

View file

@ -202,3 +202,10 @@ def restore(archive_path,root):
save(root,name,raw,captured)
if seen!=set(expected):raise Refused()
return manifest,checks(root,captured)
def require_runtime_host():
import socket
host=profile()['runtime_host']
if (os.geteuid()!=0 or socket.gethostname()!=host['hostname']
or hashlib.sha256(Path('/etc/machine-id').read_bytes()).hexdigest()!=host['machine_id_sha256']):raise Refused()

View file

@ -33,7 +33,7 @@ def load(name,path):
inventory=load('storage_inventory',HERE/'inventory-storage-share.py')
offsite=load('offsite',HERE/'identity-offsite.py')
FOLDER='/railiance-backups/net-kingdom-identity'
PROFILES={'publisher':(48,5),'retention':(49,9)}
PROFILES={'publisher':(48,21),'retention':(49,25)}
class Refused(Exception):pass
@ -57,7 +57,8 @@ def contract(action,expected):
or a['policy_name']!=name or a['auth']['role']!=name
or a['auth']['bound_claims']!={'service_account_names':[name],'service_account_namespaces':['sso']}
or provider['folder']!=FOLDER or provider['share_permissions']!=permission or provider['share_type']!=3
or provider['label']!='net-kingdom-identity-'+action):raise Refused()
or provider['label']!='net-kingdom-identity-'+action
or provider.get('provider_added_resharing_approved') is not True):raise Refused()
if (a.get('metadata_read') is not False or a.get('token_self_lifecycle') is not True
or a['auth'].get('audience')!='openbao' or a['auth'].get('token_no_default_policy') is not True
or any(a['auth'].get(k)!='15m' for k in ['ttl','token_max_ttl','token_explicit_max_ttl'])
@ -124,35 +125,44 @@ def boundary(client,auth,token,action,receipt):
receipt['provider_test_artifacts']=[name]
receipt['boundary_fixture_cleanup_verified']=False
try:
receipt['boundary_phase']='create_owner_fixture'
status,_=request(client,owner,auth,'PUT',payload.stdout,{'If-None-Match':'*'})
if status!=201:raise Refused()
created=True
receipt['boundary_phase']='read_public_fixture'
status,raw=request(client,public,(token,''))
if status!=200 or raw!=payload.stdout:raise Refused()
receipt['boundary_phase']='deny_public_overwrite'
status,_=request(client,public,(token,''),'PUT',payload.stdout)
if status not in (401,403):raise Refused()
denied_name='nk49-absent-'+uuid.uuid4().hex+'.age'
if action=='retention':receipt['provider_test_artifacts'].append(denied_name)
status,_=request(client,offsite.BASE+denied_name,(token,''),'PUT',payload.stdout,{'If-None-Match':'*'}) if action=='retention' else (403,b'')
if status not in (401,403):raise Refused()
receipt['boundary_phase']='public_delete'
status,_=request(client,public,(token,''),'DELETE')
if action=='publisher':
if status not in (401,403):raise Refused()
new=offsite.BASE+'nk49-boundary-'+uuid.uuid4().hex+'.age'
receipt['provider_test_artifacts'].append(new.rsplit('/',1)[-1])
receipt['boundary_phase']='create_public_fixture'
code,_=request(client,new,(token,''),'PUT',payload.stdout,{'If-None-Match':'*'})
if code!=201:raise Refused()
# This fixture belongs to the current ceremony, not retained data.
receipt['boundary_phase']='cleanup_public_fixture'
remove_fixture(client,offsite.HOST+'/remote.php/dav/files/Backup'+FOLDER+'/'+new.rsplit('/',1)[-1],auth,payload.stdout)
else:
if status!=204:raise Refused()
deleted=True
receipt['boundary_phase']='deny_parent_path'
status,_=request(client,offsite.BASE+'%2e%2e/r01-net-kingdom-pg/',(token,''))
receipt['parent_probe_status']=status
if status not in (401,403,404):raise Refused()
receipt['provider_boundary_verified']=True
finally:
if created and not deleted:
remove_fixture(client,owner,auth,payload.stdout)
receipt['owner_fixture_cleanup_verified']=True
# A rejected operation may have had an unexpected side effect. Only a
# successful complete boundary test claims cleanup; names remain in the
# receipt for owner reconciliation on every failure.

View file

@ -171,7 +171,7 @@ def main():
state=Path(a.state).absolute()
ready=False
try:
if os.geteuid()!=0 or socket.gethostname()!='railiance01':raise offsite.Refused()
capture.bundle.require_runtime_host()
capture.KUBE=['kubectl','--kubeconfig',a.kubeconfig]
uid=capture.get(None,'namespace','kube-system')['metadata']['uid']
if uid!=capture.prepare.CLUSTER_UID:raise offsite.Refused()

View file

@ -68,7 +68,7 @@ def module(name):
def owner():
if os.geteuid()!=0 or socket.gethostname()!='railiance01':raise Refused()
module('identity-bundle').require_runtime_host()
capture=module('capture-identity');capture.KUBE=['kubectl','--kubeconfig',KUBECONFIG]
if capture.get(None,'namespace','kube-system')['metadata']['uid']!=capture.prepare.CLUSTER_UID:raise Refused()

View file

@ -530,6 +530,23 @@ indexes. No maturity promotion implies live acceptance. Reviewable rollout and
hidden-key steps: `docs/bootstrap-recovery-ceremony.md`; evidence in
`docs/evidence/2026-10-16-identity-backup-implementation/`. T02 progress/T03 wait.
2026-10-16 approved live admission in progress: user approved the exact packet
(decision40bfae40) and then explicitly approved Nextcloud-added re-sharing for
publisher21/retention25 (decision5edd5203). The initial5/9 request failed closed
before KV publication when provider returned21. Scoped share26 exists under
Backup's exact new folder; it remains undelivered until native checks pass.
Owner sessions with executed children were self-revoked; a later callback timeout
ran no child and did not confirm possible-session revocation. No root fallback.
Fixed runtime guard to use railiance01's actual verified hostname, machine-ID
hash and cluster UID, with root required.52 focused checks including actual
synthetic encrypted archive/native PG restore passed. Both guarded DNS helper
exclusions applied with UID/RV/spec tests. Installed the source-bound runtime
with unit validation; timers remain disabled pending actual off-site recovery.
Provider boundary testing and ESO/native login delivery remain in progress.
No identity capture or scheduled retention has occurred. T02 progress/T03 wait.
Evidence: `docs/evidence/2026-10-16-identity-backup-live/`.
## Verify owner-approved recovery and current native callers
```task