// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
import { describe, expect, it } from 'vitest';
import {
buildPreviewContentSecurityPolicy,
collectPreviewRemoteOrigins,
injectPreviewContentSecurityPolicy,
isStaticImageSrc,
PREVIEW_CONTENT_SECURITY_POLICY,
repairGeneratedReportBraces,
stripScriptBlocks,
} from '@/lib/htmlSanitization';
describe('isStaticImageSrc', () => {
it('accepts static relative paths', () => {
expect(isStaticImageSrc('assets/home.png')).toBe(true);
});
it('rejects JS template literal expressions', () => {
expect(isStaticImageSrc('${escapeHtml(node.image)}')).toBe(false);
expect(isStaticImageSrc('assets/${node.id}.png')).toBe(false);
});
});
describe('stripScriptBlocks', () => {
it('removes script blocks so img scans skip JS template strings', () => {
const html = `
`;
expect(stripScriptBlocks(html)).not.toContain('escapeHtml');
expect(stripScriptBlocks(html)).toContain('assets/home.png');
});
});
describe('HTML preview CSP', () => {
it('replaces an agent-authored policy with the application policy', () => {
const html = injectPreviewContentSecurityPolicy(`
`);
expect(origins).toEqual([
'https://api.example',
'https://fonts.googleapis.com',
'https://fonts.gstatic.com',
'https://images.example',
'https://unpkg.com',
]);
});
it('grants only normalized HTTPS origins for an authorized preview', () => {
const policy = buildPreviewContentSecurityPolicy([
'https://unpkg.com/path/file.js',
'https://unpkg.com/another.js',
'http://insecure.example/script.js',
'not a url',
]);
expect(policy).toContain(
"script-src 'unsafe-inline' data: blob: localfile: https://unpkg.com"
);
expect(policy).toContain('connect-src https://unpkg.com');
expect(policy).not.toContain('insecure.example');
expect(policy).not.toContain('navigate-to');
});
it('injects the authorized policy without preserving an authored wildcard', () => {
const html = injectPreviewContentSecurityPolicy(
'',
['https://unpkg.com/module.js']
);
const doc = new DOMParser().parseFromString(html, 'text/html');
const policy = doc
.querySelector('meta[http-equiv="Content-Security-Policy" i]')
?.getAttribute('content');
expect(policy).toContain('https://unpkg.com');
expect(policy).not.toContain('https:;');
});
});
describe('generated report brace repair', () => {
it('preserves valid nested CSS closing braces and all following HUD rules', () => {
const html = `