Gate ESO adoption on verified predecessors and receive release custody handoff
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a126e1-76f8-7643-8cf3-e93336539ade
This commit is contained in:
codex 2026-10-11 23:25:20 +02:00
parent 3001a8148f
commit 7c79293831
4 changed files with 148 additions and 1 deletions

View file

@ -1,5 +1,5 @@
# DRAFT for railiance01 (RPF-WP-0044). Not synced by any root: move to
# ../applications/ only in this app's adoption task, with the founder's go-ahead.
# ../applications/ only after predecessor automated proof under accepted D2.
# No automated sync, no finalizer. CRDs survive Application pruning/deletion.
apiVersion: argoproj.io/v1alpha1
kind: Application

View file

@ -0,0 +1,48 @@
---
id: RPF-IN-0011
kind: intake
type: intake
title: "Prepare dedicated activity-core image-only release principal and custody"
repo: railiance-platform
lane: supervised
status: open
owner: railiance-platform
requested_by: activity-core
origin: handoff
origin_ref: ACTIVITY-WP-0041-T03
priority: high
created: "2026-10-11"
updated: "2026-10-11"
tags: [security, cross-owner, release, credential-custody]
---
Prepare and return an exact owner workplan/task binding for the already D2-authorized
`ACTIVITY-WP-0041-image-only-v1` release scope. This intake is independent of the
RPF48 gate that awaits ACT41 acceptance. It requests owner implementation and native
acceptance, not another founder approval or a secret value. RPF-WP-0036-T03 is
backup freshness work and does not supply this release identity/custody commitment.
Fixed intended Kubernetes identity is
`system:serviceaccount:activity-core:activity-core-release-broker` on estate
92.205.62.239, cluster UID a553c742-0115-43d4-99a4-a5ca56fe0786. Native read-only
metadata found no dedicated account, only default/activity-core-eso, with no matching
namespace/ArgoCD role bindings. ESO projection custody cannot be borrowed for release.
Platform must choose and independently attest the fixed Git publication identity
and exclusive broker custody, plus distinct build/review/health/retention issuer
principals and Ed25519 key custody/rotation; no local fixture key is acceptance.
Activity-core source supplies bounded health GET, 60-second durable observer,
private config/credential drift checks, actual Kubernetes username and eleven
allow/deny checks, dedicated Temporal worker, exact one-field Git publication,
targeted non-pruning Argo operations, durable rollback and sanitized audit sink.
See activity-core docs/release-runtime-owner-handoff.md and this repo's
docs/activity-core-release-admission.md for exact boundaries. Keep privileged
transport behind this reviewed broker because Application RBAC and repository-write
credentials alone cannot enforce the one-field scope.
Return source-bound owner acceptance and actual Git/Kubernetes allow/deny, custody,
revocation, independent signed receipts, continuous observer/ledger, Temporal
registration, normal release and failed-health rollback proof. No native activation
is claimed. If preparation requires attended admin authentication, stage the exact
reviewed custody command first, then place that login in the orange checklist.
Only a genuinely expanded action/access/custody scope goes to the red daily batch.

View file

@ -0,0 +1,61 @@
#!/usr/bin/env python3
"""Local, non-executing ESO adoption readiness gate. No credential or live calls."""
import argparse
from datetime import datetime,timezone
import hashlib
import json
from pathlib import Path
import re
import yaml
D2='89f1058f-33bc-47a8-8a49-0b44d426c67e'
def require(ok,reason):
if not ok:raise ValueError(reason)
def fresh(receipt,now):
stamp=datetime.fromisoformat(receipt['captured_at'].replace('Z','+00:00'))
require(stamp.tzinfo is not None and 0<=(now-stamp).total_seconds()<=300,'predecessor_proof_stale')
def source_check(app):
require(app.get('kind')=='Application' and app.get('metadata',{}).get('name')=='external-secrets' and app['metadata'].get('namespace')=='argocd','source_identity')
spec=app['spec'];source=spec['source'];require(spec.get('project')=='railiance-platform-addons' and spec.get('destination')=={'server':'https://kubernetes.default.svc','namespace':'external-secrets'},'source_destination')
require(source.get('repoURL')=='https://charts.external-secrets.io' and source.get('chart')=='external-secrets' and source.get('targetRevision')=='0.16.1' and source['helm'].get('releaseName')=='external-secrets','source_chart_pin')
values=yaml.safe_load(source['helm']['values']);require(values.get('installCRDs') is True,'install_crds')
options=values.get('crds',{}).get('annotations',{}).get('argocd.argoproj.io/sync-options','')
require(set(options.split(','))=={'Prune=false','Delete=false'},'crd_prune_delete_protection')
sync=spec.get('syncPolicy',{});require('automated' not in sync and not app['metadata'].get('finalizers'),'manual_no_finalizer')
require('ServerSideApply=true' in sync.get('syncOptions',[]),'server_side_apply')
require(not any(x in sync.get('syncOptions',[]) for x in ('Force=true','Replace=true')),'no_force_replace')
return {'chart_pin':'0.16.1','crd_prune_delete_protected':True,'manual_sync_only':True,'server_side_apply':True}
def issue_check(receipt,now):
require(receipt.get('schema_version')=='rapp-issue-core-adoption/v2' and receipt.get('passed') is True,'issue_core_adoption_missing')
fresh(receipt,now);checks=receipt['checks'];require(checks.get('estate_node_ip') is True and checks.get('argo_synced_healthy') is True and checks.get('argo_tracking') is True and checks.get('external_secret_ready') is True and checks.get('private_service') is True,'issue_core_adoption_incomplete')
require(bool(re.fullmatch(r'[0-9a-f]{40}',checks.get('source_revision',''))),'issue_core_immutable_revision')
require(all(checks.get(k)==v for k,v in {'healthz_status':200,'unauthenticated_ingest_status':401,'authenticated_ingest_status':201,'authenticated_close_status':200}.items()),'issue_core_controlled_smoke_missing')
def target_check(receipt,now):
require(receipt.get('schema_version')=='argocd-workload-adoption-proof/v1' and receipt.get('status')=='verified' and receipt.get('application')=='target-revenue','target_revenue_adoption_missing')
fresh(receipt,now);require(receipt.get('manual_apply_prune_off') is True and receipt.get('child_automation_enabled') is False,'target_revenue_adoption_incomplete')
def assess(app,issue,target,now=None):
now=now or datetime.now(timezone.utc);missing=[];checks={}
for name,fn,value in [('source',source_check,app),('RPF-WP-0044-T04',issue_check,issue),('RPF-WP-0044-T05',target_check,target)]:
try:
result=fn(value) if name=='source' else fn(value,now)
checks[name]=result if name=='source' else True
except Exception:missing.append(name)
return {'schema':'eso-adoption-readiness/v1','task':'RPF-WP-0044-T06','approval_ref':D2,'source_ready':bool(checks.get('source')),'ready_for_fresh_native_render_diff':not missing,'missing_or_invalid':missing,'checks':checks,'next_action':'fresh_native_render_diff' if not missing else 'wait_for_predecessor_automated_proof','founder_approval_required':False,'native_mutation':False,'live_or_credential_calls':False}
def main():
parser=argparse.ArgumentParser(description=__doc__);parser.add_argument('--draft',required=True,type=Path);parser.add_argument('--issue-core-proof',type=Path);parser.add_argument('--target-revenue-proof',type=Path)
args=parser.parse_args()
def load(path):
try:return json.loads(path.read_text()) if path else {}
except Exception:return {}
try:app=yaml.safe_load(args.draft.read_text());receipt=assess(app,load(args.issue_core_proof),load(args.target_revenue_proof))
except Exception:receipt={'ready_for_fresh_native_render_diff':False,'failure':'source_unverified','native_mutation':False,'live_or_credential_calls':False}
print(json.dumps(receipt,sort_keys=True));return 0 if receipt['ready_for_fresh_native_render_diff'] else 2
if __name__=='__main__':raise SystemExit(main())

View file

@ -0,0 +1,38 @@
import copy
from datetime import datetime,timezone,timedelta
import importlib.util
import json
from pathlib import Path
import unittest
import yaml
spec=importlib.util.spec_from_file_location('eso_gate',Path(__file__).resolve().parents[1]/'scripts/eso_adoption_readiness.py');gate=importlib.util.module_from_spec(spec);spec.loader.exec_module(gate)
NOW=datetime(2026,10,11,21,0,tzinfo=timezone.utc)
class ReadinessTests(unittest.TestCase):
def app(self):return yaml.safe_load((Path(__file__).resolve().parents[1]/'argocd/railiance01/drafts/external-secrets.application.yaml').read_text())
def issue(self):return {'schema_version':'rapp-issue-core-adoption/v2','passed':True,'captured_at':NOW.isoformat(),'checks':{'estate_node_ip':True,'argo_synced_healthy':True,'argo_tracking':True,'external_secret_ready':True,'private_service':True,'source_revision':'a'*40,'healthz_status':200,'unauthenticated_ingest_status':401,'authenticated_ingest_status':201,'authenticated_close_status':200}}
def target(self):return {'schema_version':'argocd-workload-adoption-proof/v1','status':'verified','application':'target-revenue','captured_at':NOW.isoformat(),'manual_apply_prune_off':True,'child_automation_enabled':False}
def test_prepared_source_cannot_skip_issue_core_dependency(self):
result=gate.assess(self.app(),{},self.target(),NOW);self.assertTrue(result['source_ready']);self.assertFalse(result['ready_for_fresh_native_render_diff']);self.assertEqual(result['missing_or_invalid'],['RPF-WP-0044-T04']);self.assertFalse(result['founder_approval_required'])
def test_complete_fresh_predecessors_allow_diff_only(self):
result=gate.assess(self.app(),self.issue(),self.target(),NOW);self.assertTrue(result['ready_for_fresh_native_render_diff']);self.assertFalse(result['native_mutation']);self.assertEqual(result['next_action'],'fresh_native_render_diff')
def test_stale_future_wrong_estate_or_missing_smoke_cannot_authorize_adoption(self):
for key,value in [('captured_at',(NOW-timedelta(minutes=6)).isoformat()),('captured_at',(NOW+timedelta(seconds=1)).isoformat())]:
issue=self.issue();issue[key]=value;self.assertFalse(gate.assess(self.app(),issue,self.target(),NOW)['ready_for_fresh_native_render_diff'])
for key,value in [('estate_node_ip',False),('argo_tracking',False),('authenticated_close_status',None),('source_revision','main')]:
issue=self.issue();issue['checks'][key]=value;self.assertFalse(gate.assess(self.app(),issue,self.target(),NOW)['ready_for_fresh_native_render_diff'])
def test_crd_guards_manual_policy_and_no_replace_required(self):
for mutation in ('guard','automation','replace','chart'):
app=self.app()
if mutation=='guard':app['spec']['source']['helm']['values']='installCRDs: true\n'
elif mutation=='automation':app['spec']['syncPolicy']['automated']={}
elif mutation=='replace':app['spec']['syncPolicy']['syncOptions'].append('Replace=true')
else:app['spec']['source']['targetRevision']='latest'
result=gate.assess(app,self.issue(),self.target(),NOW);self.assertFalse(result['source_ready']);self.assertFalse(result['ready_for_fresh_native_render_diff'])
def test_invalid_canary_fields_never_echo_values(self):
app=self.app();app['spec']['source']['helm']['values']='SECRET_CANARY';issue=self.issue();issue['private_value']='SECRET_CANARY';result=gate.assess(app,issue,{},NOW);self.assertNotIn('SECRET_CANARY',json.dumps(result))
def test_target_revenue_proof_must_be_exact_application_and_prune_off(self):
for key,value in [('application','foreign-app'),('manual_apply_prune_off',False),('child_automation_enabled',True),('status','unverified')]:
target=self.target();target[key]=value;self.assertFalse(gate.assess(self.app(),self.issue(),target,NOW)['ready_for_fresh_native_render_diff'])
if __name__=='__main__':unittest.main()