the-custodian/docs/changes/2026-11-01-scanner-json-digest/native-preflight.py
codex ed93d0b21f
Some checks are pending
CI Smoke / host-smoke (push) Waiting to run
CI Smoke / container-smoke (push) Waiting to run
Reject generated-only commits / generated-commit-guard (push) Waiting to run
docs: record fleet synchronization results and scanner blockers
2026-11-01 23:49:05 +01:00

57 lines
4.1 KiB
Python

"""Founder-run read-only scanner preflight; prints only selected public evidence."""
import subprocess,json,hashlib,pathlib,sys
NS='forgejo';NAME='forge';POD='forge-79c7fb84db-k5wtm'
EXPECTED_UID='1faefb26-cccd-4d0e-b509-70a7eb0b4f4d'
POD_UID='2c9f911a-403e-4183-a027-2b8d48742348'
BASE='/data/security/receive-secret-scan/20261027-b735d052a49f'
ADAPTER='b735d052a49fc8e9cca14cddee074c5429352ad71841eb6548459294f15683a2'
SCANNER='88f91962aa2f93ac6ab281d553b9e125f5197bbbce38f9f2437f7299c32e5509'
def k(*args):
q=subprocess.run(['kubectl',*args],capture_output=True,timeout=60)
if q.returncode:raise RuntimeError('read-only-command-failed; raw diagnostics withheld')
return q.stdout
def main():
d=json.loads(k('-n',NS,'get','deployment',NAME,'-o','json'))
if d['metadata']['uid']!=EXPECTED_UID:raise RuntimeError('deployment-identity-drift')
uid=k('-n',NS,'get','pod',POD,'-o','jsonpath={.metadata.uid}').decode()
if uid!=POD_UID:raise RuntimeError('pod-identity-drift')
spec=d['spec']['template']['spec'];inits=spec.get('initContainers',[])
candidates=[c['name'] for c in spec['containers'] if c.get('image')=='code.forgejo.org/forgejo/forgejo:11.0.3-rootless']
if len(candidates)!=1:raise RuntimeError('forge-container-ambiguous')
container=candidates[0]
guards=[(i,x) for i,x in enumerate(inits) if x['name']=='verify-secret-scanner']
if len(guards)!=1:raise RuntimeError('scanner-guard-ambiguous')
index,guard=guards[0]
volumes=spec.get('volumes',[]);selected=[(i,x) for i,x in enumerate(volumes) if x['name']=='secret-scan-template']
if len(selected)!=1:raise RuntimeError('scanner-volume-ambiguous')
vindex,volume=selected[0];cmname=volume['configMap']['name']
if cmname!='forgejo-secret-template-d1df801be39f':raise RuntimeError('template-configmap-drift')
# This exact public ConfigMap contains only the receiver hook, per owner source.
hook=k('-n',NS,'get','configmap',cmname,'-o','jsonpath={.data.hook}')
expected=('#!/bin/sh\nset +vx\nset -eu\nexec '+BASE+'/receive-secret-scan --scanner '+BASE+'/gitleaks\n').encode()
if hook!=expected:raise RuntimeError('mounted-hook-source-drift')
metadata=k('-n',NS,'exec',POD,'-c',container,'--','sh','-c',
'set -eu; test -f "$1" && test ! -L "$1"; test -f "$2" && test ! -L "$2"; sha256sum "$1" "$2"',
'sh',BASE+'/receive-secret-scan',BASE+'/gitleaks').decode().splitlines()
hashes=[s.split()[0] for s in metadata]
if hashes!=[ADAPTER,SCANNER]:raise RuntimeError('installed-scanner-artifact-drift')
nodes=json.loads(k('get','nodes','-o','json'))['items']
if len(nodes)!=1 or not any(a['address']=='92.205.62.239' for a in nodes[0]['status']['addresses']):raise RuntimeError('node-target-drift')
description=k('describe','node',nodes[0]['metadata']['name']).decode()
allocation=description.split('Allocated resources:',1)[1].split('Events:',1)[0].strip() if 'Allocated resources:' in description else None
if allocation is None:raise RuntimeError('node-headroom-unavailable')
receipt=dict(read_only=True,deployment_uid=EXPECTED_UID,pod=POD,pod_uid=POD_UID,
deployment_name=NAME,container=container,node_uid=nodes[0]['metadata']['uid'],node_name=nodes[0]['metadata']['name'],
guard_index=index,guard_command=guard.get('command'),guard_args=guard.get('args'),volume_index=vindex,
volume=volume,strategy=d['spec'].get('strategy'),resources=[dict(name=c['name'],resources=c.get('resources')) for c in spec['containers']],
old_configmap=cmname,old_hook_sha256=hashlib.sha256(hook).hexdigest(),old_adapter_sha256=ADAPTER,scanner_sha256=SCANNER,
allocated_resources=allocation)
pathlib.Path('/tmp/forge-scanner-preflight-receipt.json').write_text(json.dumps(receipt,indent=2)+'\n')
# Keep long public shell commands in the local receipt; return concise checks.
print(json.dumps({k:receipt[k] for k in ['read_only','deployment_name','deployment_uid','pod_uid','node_uid','old_configmap','old_adapter_sha256','strategy','allocated_resources']},indent=2))
print('receipt: /tmp/forge-scanner-preflight-receipt.json')
try:main()
except Exception as exc:
print('preflight refused:',str(exc) if isinstance(exc,RuntimeError) else type(exc).__name__)
sys.exit(1)