build: add Cloudflare static export and deploy config
This commit is contained in:
36
tests/integration/cloudflare-export.test.mjs
Normal file
36
tests/integration/cloudflare-export.test.mjs
Normal file
@@ -0,0 +1,36 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { assertProductionEnvironment, assertPublicFiles, renderCloudflareHeaders } from '../../scripts/export-cloudflare.mjs';
|
||||
|
||||
describe('Cloudflare production export boundary', () => {
|
||||
it('rejects benchmark flags and client-exposed environment overrides', () => {
|
||||
expect(() => assertProductionEnvironment({})).not.toThrow();
|
||||
for (const environment of [
|
||||
{ PORTFOLIO_TEST_BUILD: '1' },
|
||||
{ PORTFOLIO_TEST_TOKEN_DIGEST: 'a'.repeat(64) },
|
||||
{ VITE_PRIVATE_TOKEN: 'do-not-publish' },
|
||||
{ NODE_ENV: 'development' },
|
||||
]) expect(() => assertProductionEnvironment(environment)).toThrow(/production/i);
|
||||
});
|
||||
|
||||
it('rejects unexpected files, benchmark hooks and recognizable credentials', () => {
|
||||
const allowed = ['index.html', 'robots.txt', 'sitemap.xml', '_headers', 'assets/app-AbCd1234.js'];
|
||||
const files = new Map(allowed.map((path) => [path, Buffer.from('public content')]));
|
||||
expect(() => assertPublicFiles(files, allowed)).not.toThrow();
|
||||
for (const path of ['.env', 'assets/app.js.map', 'benchmark.json', '_headers.example', 'src/entry-client.ts']) {
|
||||
expect(() => assertPublicFiles(new Map([...files, [path, Buffer.from('private')]]), allowed)).toThrow(/inventory/i);
|
||||
}
|
||||
for (const payload of ['__portfolio_fault', '__portfolio_tier', '__portfolio_test_token', '__PORTFOLIO_PERFORMANCE__', '-----BEGIN PRIVATE KEY-----', 'ghp_' + 'x'.repeat(36)]) {
|
||||
expect(() => assertPublicFiles(new Map([...files, ['assets/app-AbCd1234.js', Buffer.from(payload)]]), allowed)).toThrow(/prohibited/i);
|
||||
}
|
||||
expect(() => assertPublicFiles(new Map([...files, ['assets/app-AbCd1234.js', Buffer.alloc(25 * 1024 * 1024 + 1)]]), allowed)).toThrow(/25 MiB/i);
|
||||
});
|
||||
|
||||
it('emits one cache policy and a CSP hash of the actual structured data', () => {
|
||||
const site = { environment: 'production', canonicalUrl: 'https://lucapislaru.ro/', buildId: 'production-test' };
|
||||
const headers = renderCloudflareHeaders(site, 'sha256-' + 'A'.repeat(43) + '=');
|
||||
expect(headers.match(/Cache-Control:/g)).toHaveLength(1);
|
||||
expect(headers).toContain('max-age=0, must-revalidate');
|
||||
expect(headers).toContain("script-src 'self' 'sha256-" + 'A'.repeat(43) + "='");
|
||||
expect(headers).not.toMatch(/noindex|immutable/);
|
||||
});
|
||||
});
|
||||
@@ -195,7 +195,13 @@ describe('content schemas', () => {
|
||||
})).toThrow(/unrecognized/i);
|
||||
});
|
||||
|
||||
it('accepts only the fixed preview canonical URL and no production hostname', () => {
|
||||
it('accepts only the fixed preview canonical URL and approved production hostname', () => {
|
||||
expect(parseSiteConfig({
|
||||
environment: 'production', canonicalUrl: 'https://lucapislaru.ro/', buildId: 'production-1',
|
||||
}).canonicalUrl).toBe('https://lucapislaru.ro/');
|
||||
for (const canonicalUrl of ['http://lucapislaru.ro/', 'https://www.lucapislaru.ro/', 'https://lucapîslaru.ro/', 'https://lucapislaru.ro/path', 'https://lucapislaru.ro/?', 'https://lucapislaru.ro.evil.test/']) {
|
||||
expect(() => parseSiteConfig({ environment: 'production', canonicalUrl, buildId: 'production-1' })).toThrow();
|
||||
}
|
||||
expect(() => parseSiteConfig({
|
||||
environment: 'preview', canonicalUrl: 'https://portfolio.example.test/', buildId: 'preview-1',
|
||||
})).toThrow(/portfolio\.localhost/i);
|
||||
|
||||
Reference in New Issue
Block a user