mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-11-02 09:13:33 +00:00
f0a704cfcd
* test: pin the order of the unauthenticated mounts against SigV4 and the throttle
* refactor: mount the OIDC and registry routes through a public-routes hook
* refactor: take the admin registration name and request-id context as gateway config
* refactor: move node discovery out of the gateway into the awsgw role
* refactor: drop the gateway config fields production never reads (Config, RootCAs, InternalSuffix)
* refactor: drop the gateway Version and Commit config fields
* refactor: compose the production gateway config in one tested function
* refactor: drop the gateway IAMService, STSService, NATSConn and ExpectedNodes config fields
Production never reads them: composeGateway builds Policy and Readiness from
its own inputs. Tests that used the config as a carrier now keep those
collaborators in gwfix.Deps, recorded per config with gwfix.WithDeps and read
back with gwfix.DepsOf. Gateway non-test code now imports nothing under
domains/, runtime/ or operator/.
Test edits are setup only: 153 GatewayConfig literals in 45 files had the four
keys moved into gwfix.WithDeps(..., gwfix.Deps{...}), and 113 field reads
became gwfix.DepsOf(x).{IAM,STS,NATS,Nodes}. No assertion changed.
Script 1, literal rewrite (balanced-brace scanner, keys moved out of the
literal):
import re,sys,subprocess,os
KEYS={'IAMService':'IAM','STSService':'STS','NATSConn':'NATS','ExpectedNodes':'Nodes'}
def scan_close(s,i):
# s[i]=='{' ; return index of matching '}' ; skips strings, runes, comments
d=0;n=len(s);k=i
while k<n:
c=s[k]
if c=='"':
k+=1
while s[k]!='"':
k+= 2 if s[k]=='\\' else 1
elif c=='`':
k=s.index('`',k+1)
elif c=="'":
k+=1
while s[k]!="'":
k+= 2 if s[k]=='\\' else 1
elif s.startswith('//',k):
k=s.index('\n',k)
continue
elif s.startswith('/*',k):
k=s.index('*/',k)+1
elif c in '{([': d+=1
elif c in '})]':
d-=1
if d==0: return k
k+=1
raise Exception('unbalanced')
def split_top(body):
parts=[];d=0;start=0;k=0;n=len(body)
while k<n:
c=body[k]
if c=='"':
k+=1
while body[k]!='"': k+= 2 if body[k]=='\\' else 1
elif c=='`': k=body.index('`',k+1)
elif c=="'":
k+=1
while body[k]!="'": k+= 2 if body[k]=='\\' else 1
elif body.startswith('//',k):
k=body.index('\n',k); continue
elif body.startswith('/*',k): k=body.index('*/',k)+1
elif c in '{([': d+=1
elif c in '})]': d-=1
elif c==',' and d==0:
parts.append(body[start:k]); start=k+1
k+=1
parts.append(body[start:])
return parts
changed={}
files=[l for l in subprocess.check_output(['git','ls-files','*.go']).decode().split() if os.path.exists(l)]
SKIP={'spinifex/gateway/gateway.go','spinifex/runtime/roles/awsgw/compose.go','spinifex/runtime/roles/awsgw/awsgw.go'}
lit=re.compile(r'(&?)((?:gateway\.)?GatewayConfig)\{')
total=0
for f in files:
if f in SKIP: continue
s=open(f).read()
if 'GatewayConfig{' not in s: continue
out=[];pos=0;cnt=0
for m in lit.finditer(s):
if m.start()<pos: continue
o=m.end()-1
c=scan_close(s,o)
body=s[o+1:c]
parts=split_top(body)
keep=[];moved=[]
for p in parts:
km=re.match(r'\s*(IAMService|STSService|NATSConn|ExpectedNodes)\s*:\s*(.*)$',p,re.S)
if km: moved.append((KEYS[km.group(1)],km.group(2).strip()))
else: keep.append(p)
if not moved: continue
# rebuild
kb=','.join(keep)
if kb.strip()=='' : kb=''
elif not kb.rstrip().endswith('\n') and '\n' in body: pass
d=', '.join(f'{k}: {v}' for k,v in moved)
new=f'gwfix.WithDeps({m.group(1)}{m.group(2)}{{{kb}}}, gwfix.Deps{{{d}}})'
if not m.group(1): new=f'gwfix.WithDeps(&{m.group(2)}{{{kb}}}, gwfix.Deps{{{d}}})' # value literals flagged below
out.append((m.start(),c+1,new)); pos=c+1; cnt+=1
if not m.group(1): print('VALUE LITERAL',f,s.count('\n',0,m.start())+1)
if not out: continue
r=[];last=0
for a,b,n in out:
r.append(s[last:a]);r.append(n);last=b
r.append(s[last:])
s2=''.join(r)
if 'testkit/gwfix"' not in s2:
s2=re.sub(r'import \(\n','import (\n\t"github.com/mulgadc/spinifex/internal/testkit/gwfix"\n',s2,1)
open(f,'w').write(s2); total+=cnt; changed[f]=cnt
print('literals rewritten',total,'files',len(changed))
Script 2, read rewrite (driven by the compiler's "has no field or method"
errors for the type, so only GatewayConfig receivers are touched):
import re,subprocess,sys,collections
M={'IAMService':'IAM','STSService':'STS','NATSConn':'NATS','ExpectedNodes':'Nodes'}
def run():
env=dict(__import__('os').environ,GOWORK='off')
out=''
for tags,pk in [('',['./spinifex/gateway','./spinifex/runtime/roles/awsgw/...']),('integration',['./tests/integration/...'])]:
cmd=['go','test','-count=1','-run','NONE_X','-gcflags=-e']+(['-tags',tags] if tags else [])+pk
r=subprocess.run(cmd,capture_output=True,text=True,env=env)
out+=r.stdout+r.stderr
return out
fixed=0
for it in range(8):
out=run()
errs=re.findall(r'^(\S+\.go):(\d+):(\d+): (.*?) undefined \(type (\*?(?:gateway\.)?GatewayConfig) has no field or method (\w+)\)',out,re.M)
if not errs:
print(out[-3000:]); break
byfile=collections.defaultdict(list)
for f,l,c,expr,t,fld in errs: byfile[f].append((int(l),int(c),expr,fld))
for f,es in byfile.items():
lines=open(f).read().split('\n')
for l,c,expr,fld in sorted(set(es),reverse=True):
line=lines[l-1]
# expr like 'gw.IAMService' or 'x.y.IAMService'
new=f'gwfix.DepsOf({expr[:-len(fld)-1]}).{M[fld]}'
if expr not in line: print('MISS',f,l,expr); continue
lines[l-1]=line.replace(expr,new)
fixed+=1
s='\n'.join(lines)
if 'testkit/gwfix"' not in s:
s=re.sub(r'import \(\n','import (\n\t"github.com/mulgadc/spinifex/internal/testkit/gwfix"\n',s,count=1)
open(f,'w').write(s)
print('read sites fixed',fixed)
* docs: record the gateway mount hooks and config-field removal in the package boundary migration
* docs: fill in the 11d-1 PR number in the package boundary migration