Files
memind/mindspace-public-links.test.mjs
T
john b273bb7aa2 fix: gate public page download links before Portal release
Add a MindSpace public HTML checker for missing companion docx/PDF paths, wire it into runtime packaging and release-portal-runtime-prod.sh, and document the workflow for agents and ops.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-01 18:18:27 +08:00

75 lines
3.3 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 {
collectPublicHtmlReferences,
findMissingPublicHtmlReferences,
isDownloadLikeReference,
isFilesystemPublicReference,
scanPublicHtmlLinks,
} from './mindspace-public-links.mjs';
test('isFilesystemPublicReference skips external and absolute server paths', () => {
assert.equal(isFilesystemPublicReference('duck.docx'), true);
assert.equal(isFilesystemPublicReference('assets/hero.jpg'), true);
assert.equal(isFilesystemPublicReference('https://example.com/a.docx'), false);
assert.equal(isFilesystemPublicReference('/api/mindspace/v1/assets/a/download'), false);
assert.equal(isFilesystemPublicReference('/MindSpace/u/public/page.html'), false);
});
test('isDownloadLikeReference matches download attr and attachment extensions', () => {
assert.equal(isDownloadLikeReference('report.docx', 'href="report.docx" download'), true);
assert.equal(isDownloadLikeReference('assets/chart.png', 'src="assets/chart.png"'), false);
assert.equal(isDownloadLikeReference('data/report.pdf', 'href="data/report.pdf"'), true);
});
test('collectPublicHtmlReferences downloads-only ignores api src and cover', () => {
const html = `<!doctype html>
<head>
<meta name="mindspace-cover" content='{"cover":"assets/hero.jpg"}'>
</head>
<body>
<a href="report.docx" download>下载</a>
<img src="/api/mindspace/v1/assets/a/download?inline=1">
<a href="assets/chart.png">chart</a>
</body>`;
const all = collectPublicHtmlReferences(html, '/tmp/public');
const downloads = collectPublicHtmlReferences(html, '/tmp/public', { downloadsOnly: true });
assert.deepEqual(
all.map((item) => item.ref).sort(),
['assets/chart.png', 'assets/hero.jpg', 'report.docx'],
);
assert.deepEqual(downloads.map((item) => item.ref), ['report.docx']);
});
test('findMissingPublicHtmlReferences reports missing sibling files', () => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'ms-links-'));
const htmlPath = path.join(dir, 'report.html');
fs.writeFileSync(htmlPath, '<a href="report.docx" download>下载</a>');
const missing = findMissingPublicHtmlReferences(htmlPath, null, { downloadsOnly: true });
assert.equal(missing.length, 1);
assert.equal(missing[0].ref, 'report.docx');
fs.writeFileSync(path.join(dir, 'report.docx'), 'doc');
assert.deepEqual(findMissingPublicHtmlReferences(htmlPath, null, { downloadsOnly: true }), []);
});
test('normalizeReferencePath decodes percent-encoded filenames', () => {
const html = '<a href="%E5%85%BB%E7%8C%AA.docx" download>x</a>';
const refs = collectPublicHtmlReferences(html, '/tmp/public', { downloadsOnly: true });
assert.equal(refs[0]?.ref, '养猪.docx');
});
test('scanPublicHtmlLinks walks MindSpace user public html files', () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'ms-root-'));
const publicDir = path.join(root, 'user-a', 'public');
fs.mkdirSync(publicDir, { recursive: true });
fs.writeFileSync(path.join(publicDir, 'page.html'), '<a href="missing.pdf" download>pdf</a>');
const issues = scanPublicHtmlLinks(root, { downloadsOnly: true });
assert.equal(issues.length, 1);
assert.match(issues[0].htmlPath, /page\.html$/);
assert.equal(issues[0].ref, 'missing.pdf');
});