the-custodian/docs/changes/netkingdom-target-2026-10-18/receive-scanner-batch-r1/prepare_native.py

139 lines
8.4 KiB
Python

"""Prepare public source and conditional patch; only read/server dry-run remotely.
Reuse the existing Forgejo template patch simulator, metadata transport and
server-dry-run helper. Never replay historical Helm release values.
"""
from pathlib import Path
import copy
import hashlib
import importlib.util
import json
import re
import yaml
HERE=Path(__file__).resolve().parent
REPO=HERE.parents[3]
OLD=REPO/'docs/changes/CUST-WP-0080'
OLD_DIRECTORY='/data/security/receive-secret-scan/20261012-57a0642b6251'
OLD_HASH='57a0642b625105440fe146fceb4d244fd2dd08a75beb316831675643e6cc27ec'
OLD_CM='forgejo-secret-template-b1d7cf8cd13f'
def sha(raw):
return hashlib.sha256(raw).hexdigest()
def support():
spec=importlib.util.spec_from_file_location('existing_forge_template',OLD/'activate_forge_template.py')
module=importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
def replacement_patch(deployment, old_command, new_command, old_cm, new_cm):
spec=deployment['spec']['template']['spec']
guards=[i for i,c in enumerate(spec['initContainers']) if c['name']=='verify-secret-scanner']
volumes=[i for i,v in enumerate(spec['volumes']) if v['name']=='secret-scan-template']
if len(guards)!=1 or len(volumes)!=1:
raise ValueError('missing-or-ambiguous-existing-control')
command_path='/spec/template/spec/initContainers/'+str(guards[0])+'/command'
volume_path='/spec/template/spec/volumes/'+str(volumes[0])+'/configMap/name'
if spec['initContainers'][guards[0]]['command']!=old_command or spec['volumes'][volumes[0]]['configMap']['name']!=old_cm:
raise ValueError('existing-control-drift')
return [
{'op':'test','path':'/metadata/uid','value':deployment['metadata']['uid']},
{'op':'test','path':'/metadata/resourceVersion','value':deployment['metadata']['resourceVersion']},
{'op':'test','path':command_path,'value':old_command},
{'op':'test','path':volume_path,'value':old_cm},
{'op':'replace','path':command_path,'value':new_command},
{'op':'replace','path':volume_path,'value':new_cm},
]
def main():
t=support()
manifest=json.loads((HERE/'publication-inputs.json').read_text())
commit=json.loads((HERE/'publication-commit.json').read_text())['commit']
assert commit=='ea65606c1298db782f721f9443bafeb03cdef138'
source=Path('/home/worsch/railiance-forge')
for row in manifest['files']:
assert sha((source/row['path']).read_bytes())==row['sha256']
binary=Path('/tmp/custodian-receive-scanner-batch-r1/candidate-hook')
binary_hash=sha(binary.read_bytes())
assert binary_hash=='73ee04078786801fc74d80d2bef122b7764c93856e403e8de5b078336d7f9e1a'
new_directory='/data/security/receive-secret-scan/20261018-'+binary_hash[:12]
apps=Path('/home/worsch/railiance-apps')
values_text=(apps/'helm/forgejo-values.yaml').read_text()
cm_text=(apps/'manifests/forgejo-secret-scan-template.yaml').read_text()
original_values=yaml.safe_load(values_text)
original_cm=yaml.safe_load(cm_text)
assert original_cm['metadata']['name']==OLD_CM and original_cm['immutable'] is True
old_hook=original_cm['data']['hook']
assert sha(old_hook.encode())=='b1d7cf8cd13feafe44e45876b1de3fdd9c88339d8d45791fa2b9f72ca832932b'
new_hook=old_hook.replace(OLD_DIRECTORY,new_directory)
hook_hash=sha(new_hook.encode())
new_cm='forgejo-secret-template-'+hook_hash[:12]
new_values_text=values_text.replace(OLD_DIRECTORY,new_directory).replace(OLD_HASH,binary_hash).replace(OLD_CM,new_cm)
new_cm_text=cm_text.replace(OLD_DIRECTORY,new_directory).replace(OLD_CM,new_cm).replace('FORGE-WP-0006','FORGE-WP-0010')
new_values=yaml.safe_load(new_values_text)
new_configmap=yaml.safe_load(new_cm_text)
assert new_configmap['data']['hook']==new_hook
assert len(original_values['preExtraInitContainers'])==len(new_values['preExtraInitContainers'])==1
old_command=original_values['preExtraInitContainers'][0]['command']
new_command=new_values['preExtraInitContainers'][0]['command']
# Prove the source changes only the existing guard command and CM name.
expected=copy.deepcopy(original_values)
expected['preExtraInitContainers'][0]['command']=new_command
expected['extraVolumes'][0]['configMap']['name']=new_cm
assert expected==new_values
config_expected=copy.deepcopy(original_cm)
config_expected['metadata']['name']=new_cm
config_expected['metadata']['labels']['custodian.coulomb.social/workplan']='FORGE-WP-0010'
config_expected['data']['hook']=new_hook
assert config_expected==new_configmap
nodes=json.loads(t.native.command(['get','nodes','-o','json']))['items']
assert len(nodes)==1 and any(a['type']=='InternalIP' and a['address']=='92.205.62.239' for a in nodes[0]['status']['addresses'])
d=t.deployment()
assert d['metadata']['uid']=='e8eff0aa-64bb-4b44-9a80-a66612986355'
assert d['spec']['replicas']==1 and d['spec']['strategy']['type']=='Recreate'
before=t.digest(d['spec']['template'])
forward=replacement_patch(d,old_command,new_command,OLD_CM,new_cm)
simulated=t.apply_locally(d,forward)
# Rollback reads fresh metadata, verifies exact new fields, restores the two
# original fields. This simulation changes no image, environment or mounts.
reverse=replacement_patch(simulated,new_command,old_command,new_cm,OLD_CM)
restored=t.apply_locally(simulated,reverse)
assert restored==d
dry=t.patch_remote(forward,dry_run=True)
assert t.digest(dry['spec']['template'])==t.digest(simulated['spec']['template'])
dry_cm=json.loads(t.native.command(['apply','--server-side','--dry-run=server','-f','-','-o','json'],payload=json.dumps(new_configmap).encode()))
assert dry_cm['immutable'] is True and dry_cm['data']['hook']==new_hook
proposal=HERE/'native-preparation'
proposal.mkdir(exist_ok=False)
for path,text in [('helm/forgejo-values.yaml',new_values_text),('manifests/forgejo-secret-scan-template.yaml',new_cm_text)]:
output=proposal/'apps-source'/path
output.parent.mkdir(parents=True,exist_ok=True); output.write_text(text)
(proposal/'deployment-forward.json').write_text(json.dumps(forward,indent=2)+'\n')
(proposal/'configmap.json').write_text(json.dumps(new_configmap,indent=2)+'\n')
(proposal/'old-hook').write_text(old_hook)
(proposal/'new-hook').write_text(new_hook)
result={
'proposal_id':'FORGE10-RECEIVE-BATCH-20261018','revision':'preparation-1',
'source_commit':commit,'candidate_binary_sha256':binary_hash,'new_directory':new_directory,
'old_directory':OLD_DIRECTORY,'old_binary_sha256':OLD_HASH,
'old_configmap':OLD_CM,'new_configmap':new_cm,'old_hook_sha256':sha(old_hook.encode()),'new_hook_sha256':hook_hash,
'deployment_uid':d['metadata']['uid'],'generation':d['metadata']['generation'],
'original_template_sha256':before,'proposed_template_sha256':t.digest(simulated['spec']['template']),
'source_fields_only_verified':True,'conditional_forward_and_inverse_verified':True,
'deployment_server_dry_run_verified':True,'configmap_server_dry_run_verified':True,
'native_changed':False,'approval_requested':False,
'remaining':['Pinned activation/recovery executor, drift/refusal checks and resource preflight',
'Independent owner/package admission and exact founder go',
'Native exact-binary smoke, 166-hook rollout and ordinary publication proof'],
'support_hashes':{name:sha((OLD/name).read_bytes()) for name in ['activate_forge_template.py','verify_receive_native.py','activate_receive_hooks.py']},
'apps_preimage_hashes':{path:'sha256:'+sha((apps/path).read_bytes()) for path in ['helm/forgejo-values.yaml','manifests/forgejo-secret-scan-template.yaml']},
'cost_estimate_eur':0,'cost_note':'No additional infrastructure or paid service; human effort unpriced.',
'risk_note':'One existing Forgejo Recreate rollout and exact installed-hook copies; availability impact and partial rollout require guarded rollback. No credential, policy, image or database change.'
}
(proposal/'preparation.json').write_text(json.dumps(result,indent=2)+'\n')
print(json.dumps({k:result[k] for k in ['proposal_id','candidate_binary_sha256','new_configmap','conditional_forward_and_inverse_verified','deployment_server_dry_run_verified','configmap_server_dry_run_verified','native_changed','approval_requested']}))
if __name__=='__main__':
main()