79 lines
4.6 KiB
Python
79 lines
4.6 KiB
Python
"""Founder-run selected access diagnostics, never config/credentials/raw errors.
|
|
|
|
No mutation or receipt reset. Reads selected node and self-identity metadata with
|
|
the catalogued attended context. The rollout packet and failed receipt stay intact.
|
|
"""
|
|
from pathlib import Path
|
|
import importlib.util
|
|
import json
|
|
import os
|
|
import subprocess
|
|
|
|
HERE=Path(__file__).resolve().parent
|
|
R4=HERE.parent/'native-r4'
|
|
EXPECTED='64c73100f2347470fda1b8b3194dbf6a8009291d9d80223af463b3c5ecab52fd'
|
|
ADMIN=Path('/home/worsch/.kube/config-railiance01')
|
|
OUTPUT=Path('/tmp/forge-scanner-access-diagnostic-receipt.json')
|
|
|
|
|
|
def category(returncode,stderr):
|
|
if returncode==0:return 'passed'
|
|
lower=stderr.lower()
|
|
groups=[('authentication-required',[b'the server has asked for the client to provide credentials',b'must be logged in to the server',b'unauthorized',b'invalid bearer token']),
|
|
('authorization-denied',[b'forbidden']),
|
|
('certificate-validity-failure',[b'certificate has expired',b'certificate is not yet valid',b'not yet valid']),
|
|
('certificate-verification-failure',[b'x509:',b'failed to verify certificate',b'certificate signed by unknown authority']),
|
|
('client-certificate-required',[b'tls: certificate required',b'client certificate required']),
|
|
('connection-refused',[b'connection refused']),
|
|
('transport-timeout',[b'i/o timeout',b'context deadline exceeded',b'tls handshake timeout',b'timed out']),
|
|
('name-resolution',[b'no such host']),
|
|
('context-selection-failure',[b'current-context is not set',b'context was not found',b'no context exists',b'does not exist']),
|
|
('configuration-unavailable',[b'error loading config file',b'no configuration has been provided',b'no such file or directory']),
|
|
('configuration-parse-failure',[b'yaml:',b'invalid configuration']),
|
|
('credential-plugin-failure',[b'getting credentials: exec',b'exec plugin',b'no auth provider found']),
|
|
('api-unavailable',[b'serviceunavailable',b'bad gateway',b'currently unable to handle the request',b'connection reset by peer',b'eof']),
|
|
('protocol-mismatch',[b'http response to https client'])]
|
|
for name,needles in groups:
|
|
if any(n in lower for n in needles):return name
|
|
return 'unclassified-command-failure'
|
|
|
|
|
|
def selected_nodes(raw,cfg):
|
|
data=json.loads(raw);items=data.get('items',[])
|
|
matched=len(items)==1 and items[0].get('metadata',{}).get('uid')==cfg['node_uid'] and any(x.get('address')=='92.205.62.239' for x in items[0].get('status',{}).get('addresses',[]))
|
|
return {'node_count':len(items),'target_node_matches':matched}
|
|
|
|
|
|
def selected_identity(raw):
|
|
data=json.loads(raw);user=data.get('status',{}).get('userInfo',{})
|
|
return {'self_identity_read':True,'identity_is_builder':user.get('username')=='ops-mason-builder',
|
|
'identity_in_system_masters': 'system:masters' in user.get('groups',[])}
|
|
|
|
|
|
def main():
|
|
s=importlib.util.spec_from_file_location('reviewed_r4',R4/'rollout.py');m=importlib.util.module_from_spec(s);s.loader.exec_module(m)
|
|
if m.verify_packet()!=EXPECTED:raise RuntimeError('reviewed-packet-drift')
|
|
cfg=json.loads((R4.parent/'native-r2/inputs.json').read_bytes())
|
|
env=dict(os.environ,KUBECONFIG=str(ADMIN))
|
|
receipt={'read_only':True,'native_mutation':False,'rollout_packet_sha256':EXPECTED,
|
|
'catalog_route':'kubernetes-railiance01-admin','admin_file_present':ADMIN.is_file(),
|
|
'admin_file_readable':os.access(ADMIN,os.R_OK),'checks':[]}
|
|
for label,args,select in [('get-nodes',['get','nodes','-o','json'],lambda raw:selected_nodes(raw,cfg)),
|
|
('self-identity',['auth','whoami','-o','json'],selected_identity)]:
|
|
try:
|
|
q=subprocess.run(['kubectl','--request-timeout=8s',*args],capture_output=True,timeout=15,env=env)
|
|
item={'operation':label,'returncode':q.returncode,'category':category(q.returncode,q.stderr)}
|
|
if q.returncode==0:
|
|
try:item.update(select(q.stdout))
|
|
except (ValueError,TypeError,KeyError,AttributeError):item['category']='unexpected-response; raw withheld'
|
|
except subprocess.TimeoutExpired:item={'operation':label,'category':'client-command-timeout'}
|
|
receipt['checks'].append(item)
|
|
OUTPUT.write_text(json.dumps(receipt,indent=2)+'\n')
|
|
print(json.dumps(receipt,indent=2));print('receipt:',str(OUTPUT))
|
|
|
|
|
|
if __name__=='__main__':
|
|
try:main()
|
|
except Exception as error:
|
|
print(json.dumps({'result':'read-only-diagnostic-refused','reason':str(error) if isinstance(error,RuntimeError) else type(error).__name__}))
|
|
raise SystemExit(1)
|