fix: harden release gate and page delivery
Memind CI / Test, build, and release guards (push) Failing after 12m3s
Memind CI / Test, build, and release guards (push) Failing after 12m3s
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { spawnSync } from 'node:child_process';
|
||||
import fs from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import test from 'node:test';
|
||||
|
||||
const ROOT = path.resolve(new URL('..', import.meta.url).pathname);
|
||||
|
||||
test('production release verifies gate report before any 103 connection', async () => {
|
||||
const source = await fs.readFile(
|
||||
path.join(ROOT, 'scripts', 'release-portal-runtime-prod.sh'),
|
||||
'utf8',
|
||||
);
|
||||
const gateIndex = source.indexOf('verify-release-gate-report.mjs');
|
||||
const preflightIndex = source.indexOf('执行 103 只读预检');
|
||||
const uploadIndex = source.indexOf('上传 Portal runtime 到 103');
|
||||
assert.ok(gateIndex > 0, 'missing gate verifier');
|
||||
assert.ok(preflightIndex > gateIndex, '103 preflight must run after gate verification');
|
||||
assert.ok(uploadIndex > preflightIndex, 'upload must run after preflight');
|
||||
assert.match(source, /生产发布守门员禁止 --skip-tests/);
|
||||
assert.match(source, /禁止 ALLOW_PORTAL_RELEASE_SCOPE_BYPASS/);
|
||||
});
|
||||
|
||||
test('runtime builder removes every persisted path forbidden by artifact policy', async () => {
|
||||
const source = await fs.readFile(
|
||||
path.join(ROOT, 'scripts', 'build-portal-runtime.mjs'),
|
||||
'utf8',
|
||||
);
|
||||
assert.match(source, /removeForbiddenPortalRuntimePaths/);
|
||||
assert.match(source, /removeForbiddenPortalRuntimePaths\(runtimeRoot\)/);
|
||||
});
|
||||
|
||||
test('runtime builder materializes and declares required Linux ARM64 native packages', async () => {
|
||||
const source = await fs.readFile(
|
||||
path.join(ROOT, 'scripts', 'build-portal-runtime.mjs'),
|
||||
'utf8',
|
||||
);
|
||||
assert.match(source, /@resvg\/resvg-js-linux-arm64-gnu/);
|
||||
assert.match(source, /@node-rs\/argon2-linux-arm64-gnu/);
|
||||
assert.match(source, /installLinuxArm64NativePackages\(\)/);
|
||||
assert.match(source, /optionalDependencies: runtimeOptionalDependencies/);
|
||||
assert.match(source, /缺少原生 \.node 文件/);
|
||||
});
|
||||
|
||||
test('packaged runtime gate isolates persistent roots and rejects artifact mutation', async () => {
|
||||
const localStackSource = await fs.readFile(
|
||||
path.join(ROOT, 'release-gate', 'local-stack.mjs'),
|
||||
'utf8',
|
||||
);
|
||||
assert.match(localStackSource, /MEMIND_PORTAL_H5_ROOT: resolvedPortalRoot/);
|
||||
assert.match(localStackSource, /MEMIND_DEEPSEEK_DISABLE_THINKING: '0'/);
|
||||
assert.match(localStackSource, /H5_USERS_ROOT: usersRoot/);
|
||||
assert.match(localStackSource, /MINDSPACE_STORAGE_ROOT: storageRoot/);
|
||||
assert.match(localStackSource, /MEMIND_SHARED_PUBLISH_ROOT: publishRoot/);
|
||||
|
||||
for (const scriptName of [
|
||||
'run-release-gate-runtime-cold-start.mjs',
|
||||
'run-release-gate-runtime-upgrade.mjs',
|
||||
]) {
|
||||
const scriptSource = await fs.readFile(path.join(ROOT, 'scripts', scriptName), 'utf8');
|
||||
assert.match(scriptSource, /const artifactBefore = await hashArtifact\(runtimeRoot\)/);
|
||||
assert.match(scriptSource, /const artifactAfter = await hashArtifact\(runtimeRoot\)/);
|
||||
assert.match(scriptSource, /artifactAfter\.sha256 !== artifactBefore\.sha256/);
|
||||
}
|
||||
});
|
||||
|
||||
test('production release rejects --skip-tests before repository or network preflight', () => {
|
||||
const result = spawnSync(
|
||||
'bash',
|
||||
[path.join(ROOT, 'scripts', 'release-portal-runtime-prod.sh'), '--skip-tests'],
|
||||
{ cwd: ROOT, encoding: 'utf8' },
|
||||
);
|
||||
assert.notEqual(result.status, 0);
|
||||
assert.match(result.stderr, /禁止 --skip-tests/);
|
||||
assert.doesNotMatch(`${result.stdout}\n${result.stderr}`, /103 只读预检/);
|
||||
});
|
||||
Reference in New Issue
Block a user