Skip to content

fix: eagerly initialise dynamic env vars from process.env at module-eval time - #1

Open
anurag6569201 wants to merge 1 commit into
qa/agent-sveltejs-kit/pr-01-16303/basefrom
qa/agent-sveltejs-kit/pr-01-16303/head
Open

anurag6569201 wants to merge 1 commit into
qa/agent-sveltejs-kit/pr-01-16303/basefrom
qa/agent-sveltejs-kit/pr-01-16303/head

Conversation

@anurag6569201

Copy link
Copy Markdown

closes sveltejs#14286

Dynamic $app/env values are normally populated when Server.init() calls set_env(). The problem is that instrumentation.server.js deliberately runs before Server.init(), so importing $app/env there gives you undefined. More subtly, instrumentation can share a chunk with application code and cause that code to evaluate early too, permanently capturing those undefined values at module scope.

Basically, instrumentation should run before the application, but not before the minimum runtime state it is allowed to observe exists.

This adds an environment initializer to builder.instrument(). Adapters provide the final env module location and generate the small platform-specific initializer; Kit handles the relative import, imports it before instrumentation, and only then dynamically imports the application entrypoint. The same ordering now applies in dev and preview.

The official adapters initialize from their native runtime source:

  • Node, Vercel serverless and Netlify serverless use process.env
  • Cloudflare uses env from cloudflare:workers
  • Netlify edge uses Deno.env.toObject()

Added tests for generated import paths, custom facades, module evaluation order, filename collisions, and a built adapter-node app reading dynamic env at instrumentation module scope.

Source merge-base: e7c74bf8227dc228cb36e822eaff5992569b830a
Source head: 91afeeed060aede8c09439926c818ec6f8d297f8

@shipwright-agent

Copy link
Copy Markdown

⛔ Shipwright · Blocked

Recommendation: do not merge PR #1 · Tier T3
Checks: 0 total · 0 needing attention

Next step: resolve the blocking findings before merge.

Findings (10)

  • CRITICAL The 'instrument' method now unconditionally checks 'existsSync(initializer)', but 'initializer' is an optional parameter. · packages/kit/src/core/adapt/builder.js:336
    • Fix: Review the cited evidence, fix the risk if confirmed, and rerun Shipwright.
  • HIGH The 'instrument' method now unconditionally checks 'existsSync(initializer)', but 'initializer' is an optional parameter. · packages/kit/src/core/adapt/builder.js:336
    • Fix: Fix the review finding before release.
  • HIGH 'createInstrumentationInitializer' writes the provider file using 'environment ?? · packages/kit/src/core/adapt/builder.js:295
    • Fix: Review the cited evidence, fix the risk if confirmed, and rerun Shipwright.
  • HIGH The generated initializer imports 'set_env' from '${serverDirectory}/env.js' and calls it with the environment object. · packages/kit/src/core/adapt/builder.js:300
    • Fix: Review the cited evidence, fix the risk if confirmed, and rerun Shipwright.
  • HIGH The generated initializer uses 'to_import_specifier' on the relative path from the initializer to the provider, but the provider path is computed relative to 'outputDirectory' whil · packages/kit/src/core/adapt/builder.js:297
    • Fix: Review the cited evidence, fix the risk if confirmed, and rerun Shipwright.
  • MEDIUM 'createInstrumentationInitializer' writes the provider file using 'environment ?? · packages/kit/src/core/adapt/builder.js:295
    • Fix: Fix the review finding before release.
  • MEDIUM The generated initializer imports 'set_env' from '${serverDirectory}/env.js' and calls it with the environment object. · packages/kit/src/core/adapt/builder.js:300
    • Fix: Fix the review finding before release.
  • MEDIUM The generated initializer uses 'to_import_specifier' on the relative path from the initializer to the provider, but the provider path is computed relative to 'outputDirectory' whil · packages/kit/src/core/adapt/builder.js:297
    • Fix: Fix the review finding before release.
  • …and 2 more findings in the check details.

Fireworks usage: 37,049 input · 1,204 output · 38,253 total tokens · $0.0089 · 16s · 0 fix iteration(s)

Open the Shipwright check for full evidence and the audit bundle. Use /shipwright rerun to verify again.

`Entrypoint file ${entrypoint} not found. This is probably a bug in your adapter.`
);
}
if (!existsSync(initializer)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shipwright · CRITICAL

The 'instrument' method now unconditionally checks 'existsSync(initializer)', but 'initializer' is an optional parameter.

Impact: The 'instrument' method now unconditionally checks 'existsSync(initializer)', but 'initializer' is an optional parameter. Any existing adapter that calls 'builder.instrument' without passing 'initializer' will now throw 'Instrumentation initializer undefined not found', breaking the API for all non-updated adapters. The diff does not add a default or guard for the missing parameter.

Suggested fix: Review the cited evidence, fix the risk if confirmed, and rerun Shipwright.

`Entrypoint file ${entrypoint} not found. This is probably a bug in your adapter.`
);
}
if (!existsSync(initializer)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shipwright · HIGH

The 'instrument' method now unconditionally checks 'existsSync(initializer)', but 'initializer' is an optional parameter.

Impact: The 'instrument' method now unconditionally checks 'existsSync(initializer)', but 'initializer' is an optional parameter. Any existing adapter that calls 'builder.instrument' without passing 'initializer' will now throw 'Instrumentation initializer undefined not found', breaking the API for all non-updated adapters. The diff does not add a default or guard for the missing parameter.

Suggested fix: Fix the review finding before release.

serverDirectory = `${config.outDir}/output/server`
}) {
const provider = path.join(outputDirectory, '__sveltekit_env.js');
write(provider, environment ?? 'export default process.env;');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shipwright · HIGH

'createInstrumentationInitializer' writes the provider file using 'environment ??

Impact: 'createInstrumentationInitializer' writes the provider file using 'environment ?? 'export default process.env;''. If 'environment' is an empty string (a valid falsy value that could be intentionally supplied), it silently falls back to 'process.env' instead of using the provided empty environment, causing incorrect env population.

Suggested fix: Review the cited evidence, fix the risk if confirmed, and rerun Shipwright.

const initializer = path.join(outputDirectory, '__sveltekit_env_init.js');
write(
initializer,
create_env_module({

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shipwright · HIGH

The generated initializer imports 'set_env' from '${serverDirectory}/env.js' and calls it with the environment object.

Impact: The generated initializer imports 'set_env' from '${serverDirectory}/env.js' and calls it with the environment object. If 'env.js' does not exist or does not export 'set_env', the generated module will fail at runtime. The method does not verify that 'serverDirectory/env.js' exists before generating the initializer, so adapters using a custom 'serverDirectory' without an 'env.js' will produce a broken build.

Suggested fix: Review the cited evidence, fix the risk if confirmed, and rerun Shipwright.

const provider = path.join(outputDirectory, '__sveltekit_env.js');
write(provider, environment ?? 'export default process.env;');

const initializer = path.join(outputDirectory, '__sveltekit_env_init.js');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shipwright · HIGH

The generated initializer uses 'to_import_specifier' on the relative path from the initializer to the provider, but the provider path is computed relative to 'outputDirectory' whil

Impact: The generated initializer uses 'to_import_specifier' on the relative path from the initializer to the provider, but the provider path is computed relative to 'outputDirectory' while the initializer is also in 'outputDirectory'. If 'outputDirectory' is not the same as the directory containing the entrypoint, the relative path may be incorrect, causing the import to fail at runtime.

Suggested fix: Review the cited evidence, fix the risk if confirmed, and rerun Shipwright.

serverDirectory = `${config.outDir}/output/server`
}) {
const provider = path.join(outputDirectory, '__sveltekit_env.js');
write(provider, environment ?? 'export default process.env;');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shipwright · MEDIUM

'createInstrumentationInitializer' writes the provider file using 'environment ??

Impact: 'createInstrumentationInitializer' writes the provider file using 'environment ?? 'export default process.env;''. If 'environment' is an empty string (a valid falsy value that could be intentionally supplied), it silently falls back to 'process.env' instead of using the provided empty environment, causing incorrect env population.

Suggested fix: Fix the review finding before release.

const initializer = path.join(outputDirectory, '__sveltekit_env_init.js');
write(
initializer,
create_env_module({

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shipwright · MEDIUM

The generated initializer imports 'set_env' from '${serverDirectory}/env.js' and calls it with the environment object.

Impact: The generated initializer imports 'set_env' from '${serverDirectory}/env.js' and calls it with the environment object. If 'env.js' does not exist or does not export 'set_env', the generated module will fail at runtime. The method does not verify that 'serverDirectory/env.js' exists before generating the initializer, so adapters using a custom 'serverDirectory' without an 'env.js' will produce a broken build.

Suggested fix: Fix the review finding before release.

const provider = path.join(outputDirectory, '__sveltekit_env.js');
write(provider, environment ?? 'export default process.env;');

const initializer = path.join(outputDirectory, '__sveltekit_env_init.js');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shipwright · MEDIUM

The generated initializer uses 'to_import_specifier' on the relative path from the initializer to the provider, but the provider path is computed relative to 'outputDirectory' whil

Impact: The generated initializer uses 'to_import_specifier' on the relative path from the initializer to the provider, but the provider path is computed relative to 'outputDirectory' while the initializer is also in 'outputDirectory'. If 'outputDirectory' is not the same as the directory containing the entrypoint, the relative path may be incorrect, causing the import to fail at runtime.

Suggested fix: Fix the review finding before release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant