import fs from 'node:fs' const config=JSON.parse(fs.readFileSync('contracts/configuration/kbx.configuration.json','utf8')) const artifact=JSON.parse(fs.readFileSync('deploy/kbx/release-artifact.contract.json','utf8')) const errors=[] if(!artifact.immutableArtifact)errors.push('release artifact must be immutable across promoted environments') if(!artifact.environmentSpecificConfigurationExternal)errors.push('environment configuration must stay outside the promoted artifact') if(JSON.stringify(artifact.promotionOrder)!==JSON.stringify(['Staging','Production']))errors.push('promotion order must remain Staging -> Production') for(const evidence of ['generated/release-impact.json','generated/configuration-manifest.json','generated/test-scenario-manifest.json','generated/api-manifest.json'])if(!artifact.requiredEvidence.includes(evidence))errors.push(`release artifact evidence missing ${evidence}`) const prod=config.environments.find(x=>x.id==='Production') for(const gate of ['configuration-validation','migration-dry-run','release-governance'])if(!prod?.requiredGates.includes(gate))errors.push(`Production profile missing gate ${gate}`) for(const env of config.environments){ const p=`deploy/kbx/environments/${env.id.toLowerCase()}.env.example` if(!fs.existsSync(p)){errors.push(`missing environment example ${p}`);continue} const text=fs.readFileSync(p,'utf8') const envKey=`KBX__Runtime__Environment=${env.id}` if(!text.includes(envKey))errors.push(`${p} must pin ${envKey}`) if(['Staging','Production'].includes(env.id)&&!text.includes('KBX__Database__MigrationsMode=predeploy'))errors.push(`${p} must use predeploy migrations`) if(env.id==='Production'&&!text.includes('KBX__Security__RequireHttps=true'))errors.push('production env example must require HTTPS') } const workflow=fs.readFileSync('.gitea/workflows/kbx-quality-gate.yaml','utf8') if(!workflow.includes('generated/') && !workflow.includes('generated/configuration-manifest.json'))errors.push('quality gate drift list must include generated configuration manifest') if(!workflow.includes('deploy/kbx/'))errors.push('quality gate drift list must include deployment contract outputs') const readiness='.gitea/workflows/kbx-release-readiness.yaml' if(!fs.existsSync(readiness))errors.push('missing release readiness workflow') else { const text=fs.readFileSync(readiness,'utf8') for(const token of ['validate-kbx.mjs','migration','configuration'])if(!text.toLowerCase().includes(token.toLowerCase()))errors.push(`release readiness workflow missing ${token}`) } if(errors.length){console.error('deployment governance FAIL');for(const e of errors)console.error(`- ${e}`);process.exit(1)} console.log(`deployment governance PASS: immutable artifact promotion, environments=${config.environments.length}`)