test(ql3): prove legacy env replay across promotion

This commit is contained in:
whyour
2026-08-24 22:33:15 +08:00
parent 4cf806b4b2
commit a64d08bda1
7 changed files with 696 additions and 6 deletions
@@ -6,6 +6,28 @@ const {
auditPostgresHaEvidence,
} = require('../../scripts/ql3-postgres-ha-evidence-audit.cjs');
function legacyEnvApplicationFacts() {
return {
receiptDigest: '1'.repeat(64),
taskCount: 1,
triggerCount: 1,
taskRevision: 3,
taskContentDigest: '2'.repeat(64),
executionContentDigest: '3'.repeat(64),
triggerRevision: 2,
triggerContentDigest: '4'.repeat(64),
triggerTaskRevision: 3,
triggerTaskContentDigest: '5'.repeat(64),
scheduleRevision: 2,
scheduleStateVersion: 1,
scheduleClaimVersion: 1,
planRows: 1,
receiptRows: 1,
taskItemRows: 1,
triggerItemRows: 1,
};
}
function fixture(architecture = 'arm64') {
const gates = { passed: true };
for (let index = 0; index < 100; index += 1) gates[`gate${index}`] = true;
@@ -66,12 +88,25 @@ function fixture(architecture = 'arm64') {
synchronousState: 'sync',
rejoinedAsWritablePrimary: false,
},
clusterLegacyEnvMigrationApplication: {
primaryBeforePromotion: legacyEnvApplicationFacts(),
standbyBeforePromotion: legacyEnvApplicationFacts(),
promotedAfterReplay: legacyEnvApplicationFacts(),
replicatedBeforePromotion: true,
exactReplayAfterPromotion: true,
replayStatus: 'existing',
mutationStreamsOpenedAfterPromotion: 0,
durableRowsAddedByReplay: 0,
contentFree: true,
},
timeline: [
'primary_ready',
'standby_streaming',
'synchronous_remote_apply_ready',
'cluster_legacy_env_application_replicated',
'replication_partition_and_promotion_guard_verified',
'old_primary_fenced_and_admission_withdrawn',
'cluster_legacy_env_application_replayed_after_promotion',
'standby_promoted_old_primary_rejoined_endpoint_switched',
'two_fresh_control_replicas_ready',
].map((state, atMs) => ({ state, atMs })),
@@ -92,11 +127,18 @@ test('rejects false gates, promotion drift and hidden private material', () => {
const report = fixture();
report.gates.oldPrimaryFencedBeforePromotion = false;
report.replication.promotedPrimaryTimeline = 1;
report.clusterLegacyEnvMigrationApplication.promotedAfterReplay.receiptRows = 2;
report.privateValue = 'postgresql://private-credential';
const result = auditPostgresHaEvidence(report);
assert.equal(result.compatible, false);
assert.ok(result.findings.includes('GATE_FAILED'));
assert.ok(result.findings.includes('PROMOTION_TIMELINE_INVALID'));
assert.ok(
result.findings.includes('CLUSTER_LEGACY_ENV_APPLICATION_FACTS_DRIFTED'),
);
assert.ok(
result.findings.includes('CLUSTER_LEGACY_ENV_APPLICATION_FACTS_NOT_EXACT'),
);
assert.ok(result.findings.includes('PRIVATE_MATERIAL_PRESENT'));
});
@@ -109,3 +151,27 @@ test('rejects reordered timeline and limitations drift', () => {
assert.ok(result.findings.includes('LIMITATIONS_DRIFTED'));
assert.ok(result.findings.some((finding) => finding.startsWith('TIMELINE_')));
});
test('rejects missing, widened or private Legacy Env replay evidence', () => {
const missing = fixture();
delete missing.clusterLegacyEnvMigrationApplication;
assert.ok(
auditPostgresHaEvidence(missing).findings.includes(
'CLUSTER_LEGACY_ENV_APPLICATION_EVIDENCE_MISSING',
),
);
const widened = fixture();
widened.clusterLegacyEnvMigrationApplication.privateRef =
'qlsecret:v1:private';
widened.clusterLegacyEnvMigrationApplication.primaryBeforePromotion.secretRef =
'ha-legacy-env-bundle-private';
const result = auditPostgresHaEvidence(widened);
assert.ok(
result.findings.includes('CLUSTER_LEGACY_ENV_APPLICATION_EVIDENCE_WIDENED'),
);
assert.ok(
result.findings.includes('CLUSTER_LEGACY_ENV_APPLICATION_FACTS_WIDENED'),
);
assert.ok(result.findings.includes('PRIVATE_MATERIAL_PRESENT'));
});