202 lines
8.1 KiB
JavaScript
202 lines
8.1 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import fs from 'node:fs';
|
|
import os from 'node:os';
|
|
import path from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
import {
|
|
buildPublicUrl,
|
|
buildPublicZonePageUrl,
|
|
buildPublishConstraints,
|
|
buildSandboxSessionConstraints,
|
|
ensureUserPublishLayout,
|
|
renderWorkspaceHints,
|
|
isPathInsidePublishDir,
|
|
migrateUserPublishDir,
|
|
PUBLISH_ROOT_DIR,
|
|
PUBLIC_ZONE_DIR,
|
|
resolveLegacyPublishDir,
|
|
resolveGoosedSandboxRoot,
|
|
resolvePageDataDeliveryBaseUrl,
|
|
} from './user-publish.mjs';
|
|
import { syncSkillsToWorkspace } from './skills-registry.mjs';
|
|
import { listPlatformSkillCatalog } from './skills-registry.mjs';
|
|
|
|
const USER_ID = 'a6fb1e97-2b0f-447b-b138-4561d8e5c53e';
|
|
|
|
test('publish dir and public url use stable user id', () => {
|
|
const platformRoot = path.dirname(fileURLToPath(import.meta.url));
|
|
const h5Root = fs.mkdtempSync(path.join(os.tmpdir(), 'h5-'));
|
|
const layout = ensureUserPublishLayout({
|
|
h5Root,
|
|
publicBaseUrl: 'https://m.tkmind.cn',
|
|
user: { id: USER_ID, username: 'john' },
|
|
});
|
|
assert.equal(layout.slug, USER_ID);
|
|
assert.equal(layout.username, 'john');
|
|
assert.ok(layout.publishDir.endsWith(`${path.sep}${PUBLISH_ROOT_DIR}${path.sep}${USER_ID}`));
|
|
assert.equal(
|
|
resolveGoosedSandboxRoot(h5Root, { id: USER_ID, username: 'john' }),
|
|
layout.publishDir,
|
|
);
|
|
assert.equal(
|
|
resolveGoosedSandboxRoot(h5Root, { id: USER_ID, username: 'john' }, {
|
|
MEMIND_SHARED_PUBLISH_ROOT: '/shared/MindSpace',
|
|
}),
|
|
path.join('/shared/MindSpace', USER_ID),
|
|
);
|
|
assert.equal(layout.publicUrl, `https://m.tkmind.cn/${PUBLISH_ROOT_DIR}/${USER_ID}/`);
|
|
assert.equal(
|
|
buildPublicUrl('https://m.tkmind.cn', USER_ID, 'report.html'),
|
|
`https://m.tkmind.cn/${PUBLISH_ROOT_DIR}/${USER_ID}/report.html`,
|
|
);
|
|
assert.equal(
|
|
buildPublicZonePageUrl('https://m.tkmind.cn', USER_ID, 'report.html'),
|
|
`https://m.tkmind.cn/${PUBLISH_ROOT_DIR}/${USER_ID}/${PUBLIC_ZONE_DIR}/report.html`,
|
|
);
|
|
assert.equal(
|
|
buildPublicZonePageUrl('https://m.tkmind.cn', USER_ID, `${PUBLIC_ZONE_DIR}/report.html`),
|
|
`https://m.tkmind.cn/${PUBLISH_ROOT_DIR}/${USER_ID}/${PUBLIC_ZONE_DIR}/report.html`,
|
|
);
|
|
const catalog = listPlatformSkillCatalog(platformRoot);
|
|
syncSkillsToWorkspace({
|
|
h5Root: platformRoot,
|
|
publishDir: layout.publishDir,
|
|
skillMap: { 'static-page-publish': true },
|
|
catalog,
|
|
user: { id: USER_ID, username: 'john' },
|
|
publicBaseUrl: 'https://m.tkmind.cn',
|
|
});
|
|
const skillPath = path.join(layout.publishDir, '.agents', 'skills', 'static-page-publish', 'SKILL.md');
|
|
const docxSkillPath = path.join(layout.publishDir, '.agents', 'skills', 'docx-generate', 'SKILL.md');
|
|
const longImageSkillPath = path.join(layout.publishDir, '.agents', 'skills', 'long-image-download', 'SKILL.md');
|
|
const docxScriptPath = path.join(layout.publishDir, '.agents', 'skills', 'docx-generate', 'generate_docx.py');
|
|
assert.ok(fs.existsSync(skillPath));
|
|
assert.ok(fs.existsSync(docxSkillPath));
|
|
assert.ok(fs.existsSync(longImageSkillPath));
|
|
assert.ok(fs.existsSync(docxScriptPath));
|
|
const skillText = fs.readFileSync(skillPath, 'utf8');
|
|
const docxSkillText = fs.readFileSync(docxSkillPath, 'utf8');
|
|
const longImageSkillText = fs.readFileSync(longImageSkillPath, 'utf8');
|
|
assert.match(skillText, new RegExp(`m\\.tkmind\\.cn/${PUBLISH_ROOT_DIR}/${USER_ID}/${PUBLIC_ZONE_DIR}/`));
|
|
assert.match(skillText, /public\/report\.html/);
|
|
assert.match(skillText, /\[.*\]\(.*\)/);
|
|
assert.match(skillText, /mindspace-cover/);
|
|
assert.match(skillText, /\.thumbnail\.svg/);
|
|
assert.match(skillText, /docx-generate/);
|
|
assert.match(skillText, /long-image-download/);
|
|
assert.match(skillText, /generate_long_image/);
|
|
assert.match(skillText, /禁止使用 `localStorage`/);
|
|
assert.match(skillText, /IndexedDB/);
|
|
assert.match(skillText, /PostgreSQL schema/);
|
|
assert.match(skillText, /page-data-collect/);
|
|
assert.match(docxSkillText, /public\/文件名\.docx/);
|
|
assert.match(longImageSkillText, /public\/report\.long\.png/);
|
|
assert.match(skillText, /report\.docx|伴生下载/);
|
|
});
|
|
|
|
test('migrateUserPublishDir merges legacy username directory', () => {
|
|
const h5Root = fs.mkdtempSync(path.join(os.tmpdir(), 'h5-'));
|
|
const legacyDir = resolveLegacyPublishDir(h5Root, { username: 'john' });
|
|
fs.mkdirSync(legacyDir, { recursive: true });
|
|
fs.writeFileSync(path.join(legacyDir, 'legacy.html'), '<html></html>');
|
|
const layout = ensureUserPublishLayout({
|
|
h5Root,
|
|
publicBaseUrl: 'https://m.tkmind.cn',
|
|
user: { id: USER_ID, username: 'john' },
|
|
});
|
|
assert.ok(fs.existsSync(path.join(layout.publishDir, 'legacy.html')));
|
|
});
|
|
|
|
test('buildPublishConstraints scopes default search to user workspace', () => {
|
|
const publishDir = `/var/h5/${PUBLISH_ROOT_DIR}/${USER_ID}`;
|
|
const constraints = buildPublishConstraints({
|
|
slug: USER_ID,
|
|
username: 'john',
|
|
displayName: 'John',
|
|
publicBaseUrl: 'https://m.tkmind.cn',
|
|
publishDir,
|
|
});
|
|
assert.match(constraints, /唯一文件根目录/);
|
|
assert.match(constraints, /禁止把用户叫作 TKMind/);
|
|
assert.match(constraints, /\*\*John\*\*/);
|
|
assert.doesNotMatch(constraints, /对用户统一称 \*\*TKMind\*\*/);
|
|
assert.match(constraints, /禁止用公网 URL 列目录/);
|
|
assert.match(constraints, /public\/页面\.html/);
|
|
assert.match(constraints, /docx-generate/);
|
|
assert.match(constraints, /public\/\*\.docx/);
|
|
assert.match(constraints, /long-image-download/);
|
|
assert.match(constraints, /generate_long_image/);
|
|
assert.match(constraints, /\/public\//);
|
|
});
|
|
|
|
test('buildSandboxSessionConstraints documents shell and forbids public url browsing', () => {
|
|
const text = buildSandboxSessionConstraints({
|
|
baseConstraints: 'base',
|
|
developerTools: ['write', 'edit', 'shell', 'tree'],
|
|
});
|
|
assert.match(text, /shell 已开启/);
|
|
assert.match(text, /禁止.*curl/);
|
|
assert.match(text, /list_dir 可用/);
|
|
assert.match(text, /public\/xxx\.html/);
|
|
assert.match(text, /docx-generate/);
|
|
assert.match(text, /public\/\*\.docx/);
|
|
assert.match(text, /\/public\//);
|
|
assert.match(text, /当前用户专属 PostgreSQL 数据空间/);
|
|
assert.match(text, /localStorage/);
|
|
assert.match(text, /IndexedDB/);
|
|
assert.match(text, /write_file\/edit_file 会直接拒绝/);
|
|
});
|
|
|
|
test('sandbox MCP constraints use namespaced file tools', () => {
|
|
const text = buildSandboxSessionConstraints({
|
|
baseConstraints: 'base',
|
|
developerTools: ['write_file', 'edit_file', 'read_file'],
|
|
});
|
|
assert.match(text, /sandbox-fs__write_file/);
|
|
assert.match(text, /sandbox-fs__edit_file/);
|
|
assert.match(text, /禁止调用不存在的裸 `write_file`/);
|
|
});
|
|
|
|
test('renderWorkspaceHints includes docx download guidance for published pages', () => {
|
|
const text = renderWorkspaceHints({
|
|
slug: USER_ID,
|
|
username: 'john',
|
|
publishDir: `/var/h5/${PUBLISH_ROOT_DIR}/${USER_ID}`,
|
|
displayName: 'John',
|
|
});
|
|
assert.match(text, /docx-generate/);
|
|
assert.match(text, /public\/\*\.docx/);
|
|
assert.match(text, /long-image-download/);
|
|
assert.match(text, /generate_long_image/);
|
|
assert.match(text, /apps__create_app/);
|
|
assert.match(text, /Page Data API/);
|
|
assert.match(text, /asset\.htmlSrc/);
|
|
assert.match(text, /workspaceRelativePath.*禁止直接写入 HTML/);
|
|
assert.match(text, /未验证文件已落盘/);
|
|
});
|
|
|
|
test('isPathInsidePublishDir blocks escape', () => {
|
|
const publishDir = `/var/h5/${PUBLISH_ROOT_DIR}/${USER_ID}`;
|
|
assert.equal(isPathInsidePublishDir(publishDir, `/var/h5/${PUBLISH_ROOT_DIR}/${USER_ID}/report.html`), true);
|
|
assert.equal(isPathInsidePublishDir(publishDir, `/var/h5/${PUBLISH_ROOT_DIR}/other-id/x.html`), false);
|
|
});
|
|
|
|
test('resolvePageDataDeliveryBaseUrl prefers Portal when public base points at local Vite', () => {
|
|
assert.equal(
|
|
resolvePageDataDeliveryBaseUrl({ H5_PUBLIC_BASE_URL: 'http://127.0.0.1:5173', H5_PORT: '8081' }),
|
|
'http://127.0.0.1:8081',
|
|
);
|
|
assert.equal(
|
|
resolvePageDataDeliveryBaseUrl({
|
|
MEMIND_PAGE_DATA_DELIVERY_BASE_URL: 'http://127.0.0.1:8081',
|
|
H5_PUBLIC_BASE_URL: 'http://127.0.0.1:5173',
|
|
}),
|
|
'http://127.0.0.1:8081',
|
|
);
|
|
assert.equal(
|
|
resolvePageDataDeliveryBaseUrl({ H5_PUBLIC_BASE_URL: 'https://m.tkmind.cn' }),
|
|
'https://m.tkmind.cn',
|
|
);
|
|
});
|