mirror of
https://github.com/Traceworks2023/nxtgauge-gitops.git
synced 2026-06-11 14:00:10 +00:00
fix(registry): protect base images (alpine, node, rust) from retention script
This commit is contained in:
parent
827477ac3f
commit
3595de89c3
1 changed files with 38 additions and 9 deletions
|
|
@ -9,22 +9,51 @@ data:
|
|||
REG='https://registry.nxtgauge.com'
|
||||
CFG='/auth/.dockerconfigjson'
|
||||
PATTERN=re.compile(r'^[0-9a-f]{40}$')
|
||||
|
||||
|
||||
# Base images that MUST NEVER be deleted, even if their names start with
|
||||
# nxtgauge- in the future. These are the FROM lines in our Dockerfiles
|
||||
# (alpine for rust, node variants for frontend/admin, etc.). If any of
|
||||
# these are missing the entire build pipeline breaks.
|
||||
BASE_IMAGES = {
|
||||
'alpine',
|
||||
'node',
|
||||
'rust',
|
||||
'busybox',
|
||||
'golang',
|
||||
'nginx',
|
||||
'postgres',
|
||||
'redis',
|
||||
}
|
||||
# Project-image prefix that we DO prune. Anything outside this is sacred.
|
||||
PROJECT_PREFIX = 'nxtgauge-'
|
||||
|
||||
with open(CFG,'r') as f:
|
||||
dcfg=json.load(f)
|
||||
auth=dcfg['auths']['registry.nxtgauge.com']['auth']
|
||||
HEAD={'Authorization': f'Basic {auth}'}
|
||||
|
||||
|
||||
def req(url, headers=None, method='GET'):
|
||||
h=dict(HEAD)
|
||||
if headers: h.update(headers)
|
||||
r=urllib.request.Request(url, headers=h, method=method)
|
||||
with urllib.request.urlopen(r, timeout=30) as resp:
|
||||
return resp.status, dict(resp.headers), resp.read()
|
||||
|
||||
|
||||
_, _, body = req(f'{REG}/v2/_catalog?n=1000')
|
||||
repos=[r for r in json.loads(body.decode()).get('repositories',[]) if r.startswith('nxtgauge-')]
|
||||
|
||||
all_repos=json.loads(body.decode()).get('repositories',[])
|
||||
|
||||
# EXPLICIT SAFETY: only consider repos that match the project prefix.
|
||||
# This double-belt-and-suspenders: base images (alpine/node/rust) are
|
||||
# also in BASE_IMAGES as a fallback in case the prefix is ever changed.
|
||||
repos=[r for r in all_repos if r.startswith(PROJECT_PREFIX) and r not in BASE_IMAGES]
|
||||
|
||||
# Sanity check: log if any base image is missing
|
||||
missing_base = [b for b in BASE_IMAGES if b in all_repos or True] # always present
|
||||
present = set(all_repos)
|
||||
for b in BASE_IMAGES:
|
||||
if b not in present:
|
||||
print(f'[WARN] base image {b} not in registry catalog - re-push required!')
|
||||
|
||||
deleted=0
|
||||
for repo in sorted(repos):
|
||||
try:
|
||||
|
|
@ -33,12 +62,12 @@ data:
|
|||
except Exception as e:
|
||||
print(f'[{repo}] tags/list failed: {e}')
|
||||
continue
|
||||
|
||||
|
||||
sha=[t for t in tags if PATTERN.match(t)]
|
||||
if len(sha)<=1:
|
||||
print(f'[{repo}] sha={len(sha)} no prune')
|
||||
continue
|
||||
|
||||
|
||||
rows=[]
|
||||
for t in sha:
|
||||
created='1970-01-01T00:00:00Z'
|
||||
|
|
@ -54,7 +83,7 @@ data:
|
|||
except Exception:
|
||||
created='9999-12-31T23:59:59Z'
|
||||
rows.append((created, t, digest))
|
||||
|
||||
|
||||
rows.sort(key=lambda x: x[0], reverse=True)
|
||||
KEEP_N=3 # keep last 3 SHA builds (was 1; bumped to prevent auth-blast-radius wipeouts)
|
||||
keep_set=set(t for _, t, _ in rows[:KEEP_N])
|
||||
|
|
@ -73,5 +102,5 @@ data:
|
|||
print(f' delete failed {repo}:{t} code={e.code}')
|
||||
except Exception as e:
|
||||
print(f' delete failed {repo}:{t} err={e}')
|
||||
|
||||
|
||||
print(f'deleted_manifests={deleted}')
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue