Skip to content

Commit d012bfe

Browse files
das-peterematipico
andauthored
fix(dev): Passing on allowedDomains configuration. (#16317)
Co-authored-by: Emanuele Stoppa <my.burning@gmail.com>
1 parent 747a5b3 commit d012bfe

4 files changed

Lines changed: 236 additions & 0 deletions

File tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
'astro': patch
3+
---
4+
Fixes a bug where `allowedDomains` weren't correctly propagated when using the development server.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
'astro': patch
3+
---
4+
Adds tests to verify settings are properly propagated when using the development server.

packages/astro/src/manifest/serialized.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ async function createSerializedManifest(
201201
i18n: i18nManifest,
202202
checkOrigin:
203203
(settings.config.security?.checkOrigin && settings.buildOutput === 'server') ?? false,
204+
allowedDomains: settings.config.security?.allowedDomains,
204205
actionBodySizeLimit: settings.config.security?.actionBodySizeLimit
205206
? settings.config.security.actionBodySizeLimit
206207
: 1024 * 1024, // 1mb default
Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
import assert from 'node:assert/strict';
2+
import { describe, it } from 'node:test';
3+
import {
4+
serializedManifestPlugin,
5+
SERIALIZED_MANIFEST_RESOLVED_ID,
6+
} from '../../../dist/manifest/serialized.js';
7+
import { createBasicSettings } from '../test-utils.js';
8+
9+
/**
10+
* Invoke the plugin's load handler (as it runs in dev mode) and return the
11+
* parsed SerializedSSRManifest that is embedded in the generated module code.
12+
*/
13+
async function getManifest(settings) {
14+
const plugin = serializedManifestPlugin({ settings, command: 'dev', sync: false });
15+
const load = plugin.load;
16+
const result = await load.handler.call({}, SERIALIZED_MANIFEST_RESOLVED_ID);
17+
// The generated code contains: _deserializeManifest((<json>))
18+
const match = /_deserializeManifest\(\((.+)\)\)/s.exec(result.code);
19+
assert.ok(match, 'Could not find manifest JSON in plugin output');
20+
return JSON.parse(match[1]);
21+
}
22+
23+
describe('serializedManifestPlugin - dev mode', () => {
24+
describe('allowedDomains', () => {
25+
it('defaults to an empty array when not configured', async () => {
26+
const settings = await createBasicSettings({});
27+
const manifest = await getManifest(settings);
28+
assert.deepEqual(manifest.allowedDomains, []);
29+
});
30+
31+
it('is an empty array when configured as []', async () => {
32+
const settings = await createBasicSettings({
33+
security: { allowedDomains: [] },
34+
});
35+
const manifest = await getManifest(settings);
36+
assert.deepEqual(manifest.allowedDomains, []);
37+
});
38+
39+
it('preserves a single hostname pattern', async () => {
40+
const pattern = [{ hostname: 'example.com' }];
41+
const settings = await createBasicSettings({
42+
security: { allowedDomains: pattern },
43+
});
44+
const manifest = await getManifest(settings);
45+
assert.deepEqual(manifest.allowedDomains, pattern);
46+
});
47+
48+
it('preserves multiple patterns with protocol and port', async () => {
49+
const patterns = [
50+
{ hostname: '*.example.com', protocol: 'https' },
51+
{ hostname: 'cdn.example.com', port: '443' },
52+
];
53+
const settings = await createBasicSettings({
54+
security: { allowedDomains: patterns },
55+
});
56+
const manifest = await getManifest(settings);
57+
assert.deepEqual(manifest.allowedDomains, patterns);
58+
});
59+
});
60+
61+
describe('checkOrigin', () => {
62+
it('is false by default', async () => {
63+
const settings = await createBasicSettings({});
64+
const manifest = await getManifest(settings);
65+
assert.equal(manifest.checkOrigin, false);
66+
});
67+
68+
it('is false when checkOrigin=true but buildOutput is not server', async () => {
69+
const settings = await createBasicSettings({
70+
security: { checkOrigin: true },
71+
});
72+
settings.buildOutput = 'static';
73+
const manifest = await getManifest(settings);
74+
assert.equal(manifest.checkOrigin, false);
75+
});
76+
77+
it('is true when checkOrigin=true and buildOutput is server', async () => {
78+
const settings = await createBasicSettings({
79+
security: { checkOrigin: true },
80+
});
81+
settings.buildOutput = 'server';
82+
const manifest = await getManifest(settings);
83+
assert.equal(manifest.checkOrigin, true);
84+
});
85+
});
86+
87+
describe('actionBodySizeLimit', () => {
88+
it('defaults to 1 MB when not configured', async () => {
89+
const settings = await createBasicSettings({});
90+
const manifest = await getManifest(settings);
91+
assert.equal(manifest.actionBodySizeLimit, 1024 * 1024);
92+
});
93+
94+
it('uses the configured value', async () => {
95+
const settings = await createBasicSettings({
96+
security: { actionBodySizeLimit: 2097152 },
97+
});
98+
const manifest = await getManifest(settings);
99+
assert.equal(manifest.actionBodySizeLimit, 2097152);
100+
});
101+
});
102+
103+
describe('serverIslandBodySizeLimit', () => {
104+
it('defaults to 1 MB when not configured', async () => {
105+
const settings = await createBasicSettings({});
106+
const manifest = await getManifest(settings);
107+
assert.equal(manifest.serverIslandBodySizeLimit, 1024 * 1024);
108+
});
109+
110+
it('uses the configured value', async () => {
111+
const settings = await createBasicSettings({
112+
security: { serverIslandBodySizeLimit: 512 },
113+
});
114+
const manifest = await getManifest(settings);
115+
assert.equal(manifest.serverIslandBodySizeLimit, 512);
116+
});
117+
});
118+
119+
describe('serverLike', () => {
120+
it('is true when buildOutput is server', async () => {
121+
const settings = await createBasicSettings({});
122+
settings.buildOutput = 'server';
123+
const manifest = await getManifest(settings);
124+
assert.equal(manifest.serverLike, true);
125+
});
126+
127+
it('is false when buildOutput is static', async () => {
128+
const settings = await createBasicSettings({});
129+
settings.buildOutput = 'static';
130+
const manifest = await getManifest(settings);
131+
assert.equal(manifest.serverLike, false);
132+
});
133+
134+
it('is false when buildOutput is undefined', async () => {
135+
const settings = await createBasicSettings({});
136+
settings.buildOutput = undefined;
137+
const manifest = await getManifest(settings);
138+
assert.equal(manifest.serverLike, false);
139+
});
140+
});
141+
142+
describe('trailingSlash', () => {
143+
for (const value of ['always', 'never', 'ignore']) {
144+
it(`preserves trailingSlash="${value}"`, async () => {
145+
const settings = await createBasicSettings({ trailingSlash: value });
146+
const manifest = await getManifest(settings);
147+
assert.equal(manifest.trailingSlash, value);
148+
});
149+
}
150+
});
151+
152+
describe('base', () => {
153+
it('preserves base="/"', async () => {
154+
const settings = await createBasicSettings({ base: '/' });
155+
const manifest = await getManifest(settings);
156+
assert.equal(manifest.base, '/');
157+
});
158+
159+
it('preserves base="/subpath/"', async () => {
160+
const settings = await createBasicSettings({ base: '/subpath/' });
161+
const manifest = await getManifest(settings);
162+
assert.equal(manifest.base, '/subpath/');
163+
});
164+
});
165+
166+
describe('compressHTML', () => {
167+
it('is true by default', async () => {
168+
const settings = await createBasicSettings({});
169+
const manifest = await getManifest(settings);
170+
assert.equal(manifest.compressHTML, true);
171+
});
172+
173+
it('is false when explicitly disabled', async () => {
174+
const settings = await createBasicSettings({ compressHTML: false });
175+
const manifest = await getManifest(settings);
176+
assert.equal(manifest.compressHTML, false);
177+
});
178+
});
179+
180+
describe('i18n', () => {
181+
it('is undefined when not configured', async () => {
182+
const settings = await createBasicSettings({});
183+
const manifest = await getManifest(settings);
184+
assert.equal(manifest.i18n, undefined);
185+
});
186+
187+
it('includes expected fields when configured', async () => {
188+
const settings = await createBasicSettings({
189+
i18n: {
190+
defaultLocale: 'en',
191+
locales: ['en', 'fr'],
192+
fallback: { fr: 'en' },
193+
},
194+
});
195+
const manifest = await getManifest(settings);
196+
assert.ok(manifest.i18n, 'i18n should be defined');
197+
assert.equal(manifest.i18n.defaultLocale, 'en');
198+
assert.deepEqual(manifest.i18n.locales, ['en', 'fr']);
199+
assert.deepEqual(manifest.i18n.fallback, { fr: 'en' });
200+
assert.ok('strategy' in manifest.i18n, 'strategy should be present');
201+
assert.ok('fallbackType' in manifest.i18n, 'fallbackType should be present');
202+
assert.ok('domainLookupTable' in manifest.i18n, 'domainLookupTable should be present');
203+
});
204+
});
205+
206+
describe('key', () => {
207+
it('embeds a non-empty encoded key string', async () => {
208+
const settings = await createBasicSettings({});
209+
const manifest = await getManifest(settings);
210+
assert.ok(typeof manifest.key === 'string' && manifest.key.length > 0);
211+
});
212+
});
213+
214+
describe('directory paths', () => {
215+
it('serializes directory URLs to strings', async () => {
216+
const settings = await createBasicSettings({});
217+
const manifest = await getManifest(settings);
218+
assert.equal(typeof manifest.rootDir, 'string');
219+
assert.equal(typeof manifest.srcDir, 'string');
220+
assert.equal(typeof manifest.outDir, 'string');
221+
assert.equal(typeof manifest.cacheDir, 'string');
222+
assert.equal(typeof manifest.publicDir, 'string');
223+
assert.equal(typeof manifest.buildClientDir, 'string');
224+
assert.equal(typeof manifest.buildServerDir, 'string');
225+
});
226+
});
227+
});

0 commit comments

Comments
 (0)