fix: route portal canary through isolated edge tunnel
Memind CI / Test, build, and release guards (push) Has been cancelled

This commit is contained in:
john
2026-07-26 20:30:56 +08:00
parent 286069449b
commit 473ad80882
10 changed files with 306 additions and 122 deletions
+58 -6
View File
@@ -6,6 +6,25 @@ import test from 'node:test';
const ROOT = path.resolve(new URL('..', import.meta.url).pathname);
const CANARY_RELEASE = path.join(ROOT, 'scripts', 'release-portal-canary-prod.sh');
const CANARY_ROLLBACK = path.join(ROOT, 'scripts', 'rollback-portal-canary-prod.sh');
function heredocBody(source, opener, closer) {
const start = source.indexOf(opener);
assert.ok(start >= 0, `missing heredoc opener: ${opener}`);
const bodyStart = source.indexOf('\n', start) + 1;
const end = source.indexOf(`\n${closer}\n`, bodyStart);
assert.ok(bodyStart > 0 && end >= bodyStart, `missing heredoc closer: ${closer}`);
return source.slice(bodyStart, end);
}
function assertShellParses(source, label) {
const result = spawnSync('bash', ['-n'], {
cwd: ROOT,
encoding: 'utf8',
input: source,
});
assert.equal(result.status, 0, `${label} failed bash -n:\n${result.stderr}`);
}
test('production release verifies gate report before any 103 connection', async () => {
const source = await fs.readFile(
@@ -96,28 +115,61 @@ test('production canary keeps stable 8081 live and switches only after verified
const source = await fs.readFile(CANARY_RELEASE, 'utf8');
const fullBackup = source.indexOf('Create and verify the full stable backup');
const persistBackup = source.indexOf('Create and verify the persisted-data backup');
const edgeBackup = source.indexOf('Create and verify the active 105 nginx routing backup');
const goosedStart = source.indexOf('Start an isolated goosed candidate on 18015');
const candidateStart = source.indexOf('Start the passive candidate Portal on 18081');
const proxyStart = source.indexOf('Start the fail-closed identity router on 18080');
const tunnelSwitch = source.indexOf('Switch only the reverse tunnel');
const proxyStart = source.indexOf('Start the fail-closed identity router on 18082');
const tunnelStart = source.indexOf('Start the isolated 105 reverse tunnel on 19082');
const edgeSwitch = source.indexOf(
'Switch the committed 105 nginx upstreams to the isolated canary tunnel',
);
const fallbackProbe = source.indexOf('route-probe?username=john');
assert.ok(fullBackup > 0);
assert.ok(persistBackup > fullBackup);
assert.ok(goosedStart > persistBackup);
assert.ok(edgeBackup > persistBackup);
assert.ok(goosedStart > edgeBackup);
assert.ok(candidateStart > goosedStart);
assert.ok(proxyStart > candidateStart);
assert.ok(tunnelSwitch > proxyStart);
assert.ok(fallbackProbe > tunnelSwitch);
assert.match(source, /write_tunnel_plist 8081/);
assert.ok(tunnelStart > proxyStart);
assert.ok(edgeSwitch > tunnelStart);
assert.ok(fallbackProbe > edgeSwitch);
assert.match(source, /restore_edge_to_stable/);
assert.match(source, /proxy_pass http:\/\/58\.38\.22\.103:8081;/);
assert.match(source, /proxy_pass http:\/\/127\.0\.0\.1:\$\{CANARY_TUNNEL_REMOTE_PORT\};/);
assert.match(source, /nginx -t/);
assert.match(source, /CANARY_PROXY_PORT=18082/);
assert.match(source, /CANARY_TUNNEL_REMOTE_PORT=19082/);
assert.match(source, /CANARY_USERNAMES="john"/);
assert.match(source, /CANARY_WECHAT_USER_IDS="wx_ul610et8"/);
assert.match(source, /route-probe\?\$\{probe_query\}/);
assert.match(source, /candidate_healthy/);
assert.match(source, /MEMIND_CANARY_RELEASE_ID/);
assert.match(
source,
/if restore_edge_to_stable >\/dev\/null 2>&1; then\s+stop_candidate_services/,
);
assert.match(source, /keeping canary services running/);
assert.match(source, /--resolve wechat\.m\.tkmind\.cn:443:127\.0\.0\.1/);
assert.doesNotMatch(source, /lsof -tiTCP:8081/);
assert.doesNotMatch(source, /bootout.*cn\.tkmind\.memind-portal/);
});
test('canary release and rollback remote shells remain syntactically valid', async () => {
const releaseSource = await fs.readFile(CANARY_RELEASE, 'utf8');
const rollbackSource = await fs.readFile(CANARY_ROLLBACK, 'utf8');
const releaseRemote = heredocBody(releaseSource, "<<'REMOTE_SCRIPT'", 'REMOTE_SCRIPT');
const rollbackRemote = heredocBody(rollbackSource, "<<'REMOTE'", 'REMOTE');
const edgeSwitch = heredocBody(releaseRemote, '<<EDGE_SWITCH', 'EDGE_SWITCH')
.replaceAll('\\$', '$');
const edgeRollback = heredocBody(rollbackRemote, '<<EDGE_ROLLBACK', 'EDGE_ROLLBACK')
.replaceAll('\\$', '$');
assertShellParses(releaseRemote, 'release remote shell');
assertShellParses(rollbackRemote, 'rollback remote shell');
assertShellParses(edgeSwitch, '105 edge switch shell');
assertShellParses(edgeRollback, '105 edge rollback shell');
});
test('release readiness ignores only the generated canary artifact cover path', async () => {
const source = await fs.readFile(
path.join(ROOT, 'scripts', 'check-release-ready.sh'),