fix(release): gate channel and distribution acceptance

This commit is contained in:
key
2026-07-29 12:51:31 +08:00
parent 5ee002ddcd
commit 46f4616bd4
10 changed files with 209 additions and 8 deletions
+78
View File
@@ -54,6 +54,10 @@ const candidateFileValid = nonBlank(approval.candidateFile)
&& approval.candidateFile.endsWith('.json')
check(candidateFileValid, 'candidateFile must be a JSON basename beside the approval file')
check(sha256Pattern.test(approval.candidateSha256 ?? ''), 'candidateSha256 must be lowercase SHA-256')
check(
sha256Pattern.test(approval.expectedApkSignerSha256 ?? ''),
'expectedApkSignerSha256 must be lowercase SHA-256',
)
if (!candidateFileValid) {
for (const failure of failures) console.error(`FAIL: ${failure}`)
@@ -110,6 +114,7 @@ for (const source of sourceRegistry) {
const scenarioApprovals = approval.scenarioApprovals
const questionApprovals = approval.policyQuestionApprovals
const channelApprovals = approval.channelApprovals
check(
scenarioApprovals && typeof scenarioApprovals === 'object' && !Array.isArray(scenarioApprovals),
'scenarioApprovals must be an object keyed by candidate ID',
@@ -118,14 +123,29 @@ check(
questionApprovals && typeof questionApprovals === 'object' && !Array.isArray(questionApprovals),
'policyQuestionApprovals must be an object keyed by question ID',
)
check(
channelApprovals && typeof channelApprovals === 'object' && !Array.isArray(channelApprovals),
'channelApprovals must be an object keyed by direct-channel role',
)
const scenarioEntries = Object.entries(scenarioApprovals ?? {})
const questionEntries = Object.entries(questionApprovals ?? {})
const channelEntries = Object.entries(channelApprovals ?? {})
for (const [candidateId] of scenarioEntries) {
check(expectedScenarios.has(candidateId), `${candidateId}: approval references an unknown scenario`)
}
for (const [questionId] of questionEntries) {
check(expectedQuestions.has(questionId), `${questionId}: approval references an unknown question`)
}
const requiredChannels = [
'direct_president',
'direct_finance',
'direct_hr',
'direct_audit',
'direct_operations',
]
for (const [roleKey] of channelEntries) {
check(requiredChannels.includes(roleKey), `${roleKey}: approval references an unknown direct channel`)
}
const resolveSourceRefs = (refs, label) => {
check(Array.isArray(refs) && refs.length > 0, `${label}: at least one formal source reference is required`)
@@ -171,6 +191,7 @@ if (strict) {
check(entry.secondReviewedBy !== entry.reviewedBy, `${label}: high-risk reviewers must be different people`)
}
check(nonBlank(entry.businessEvidenceRef), `${label}: business evidence reference is required`)
check(sha256Pattern.test(entry.businessEvidenceSha256 ?? ''), `${label}: business evidence SHA-256 is required`)
check(nonBlank(entry.productionContentVersion), `${label}: production content version is required`)
check(sha256Pattern.test(entry.productionContentHash ?? ''), `${label}: production content hash is required`)
}
@@ -208,6 +229,29 @@ if (strict) {
requireReview(entry, label)
}
check(channelEntries.length === requiredChannels.length, 'channel approvals must cover exactly 5/5 roles')
for (const roleKey of requiredChannels) {
const entry = channelApprovals?.[roleKey]
const label = roleKey
check(Boolean(entry), `${label}: channel approval is missing`)
if (!entry) continue
check(entry.status === 'APPROVED', `${label}: channel status must be APPROVED`)
check(entry.minimumActiveHandlers === 2, `${label}: primary and backup requirement must remain 2`)
for (const evidenceName of [
'bindingEvidence',
'positiveAccessEvidence',
'crossChannelDenialEvidence',
'singleReplyEvidence',
]) {
check(nonBlank(entry[`${evidenceName}Ref`]), `${label}: ${evidenceName} reference is required`)
check(
sha256Pattern.test(entry[`${evidenceName}Sha256`] ?? ''),
`${label}: ${evidenceName} SHA-256 is required`,
)
}
requireReview(entry, label)
}
const requiredSignoffs = [
'businessOwner',
'knowledgeOwner',
@@ -224,6 +268,37 @@ if (strict) {
check(signoff?.status === 'APPROVED', `${role}: sign-off must be APPROVED`)
if (signoff) requireReview(signoff, role)
}
const distribution = approval.distributionApproval
check(
distribution && typeof distribution === 'object' && !Array.isArray(distribution),
'distributionApproval must be an object',
)
if (distribution) {
check(distribution.status === 'APPROVED', 'distribution approval must be APPROVED')
check(distribution.scope === 'CONTROLLED_INTERNAL_TEST', 'distribution scope must remain controlled internal test')
check(
['LEGAL_APPROVED', 'CONTROLLED_INTERNAL_TEST_EXCEPTION_ACCEPTED'].includes(distribution.legalDecision),
'distribution legalDecision is not approved',
)
check(
[
'ENTERPRISE_SIGNER_APPROVED',
'DCLOUD_TEST_SIGNER_ACCEPTED_FOR_CONTROLLED_INTERNAL_TEST',
].includes(distribution.signerDecision),
'distribution signerDecision is not approved',
)
check(
distribution.signerSha256 === approval.expectedApkSignerSha256,
'distribution signer SHA-256 must match the expected APK signer',
)
check(nonBlank(distribution.distributionEvidenceRef), 'controlled-distribution evidence reference is required')
check(
sha256Pattern.test(distribution.distributionEvidenceSha256 ?? ''),
'controlled-distribution evidence SHA-256 is required',
)
requireReview(distribution, 'distributionApproval')
}
}
if (failures.length > 0) {
@@ -243,12 +318,15 @@ if (scenarioSnapshots) {
} else {
const approvedScenarios = scenarioEntries.filter(([, value]) => value?.status === 'APPROVED').length
const approvedQuestions = questionEntries.filter(([, value]) => value?.status === 'APPROVED').length
const approvedChannels = channelEntries.filter(([, value]) => value?.status === 'APPROVED').length
const approvedSignoffs = Object.values(approval.signoffs ?? {}).filter((value) => value?.status === 'APPROVED').length
console.log('August 1 formal content approval audit passed')
console.log(`- releaseStatus: ${approval.releaseStatus}`)
console.log(`- formal sources: ${sourceRegistry.length}`)
console.log(`- approved scenarios: ${approvedScenarios}/5`)
console.log(`- approved policy questions: ${approvedQuestions}/30`)
console.log(`- approved direct channels: ${approvedChannels}/5`)
console.log(`- approved owner sign-offs: ${approvedSignoffs}/5`)
console.log(`- controlled distribution: ${approval.distributionApproval?.status ?? 'MISSING'}`)
console.log(`- strict release ready: ${strict ? 'true' : 'not requested'}`)
}