@varlock/nextjs-integration 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/dist/loader.js +88 -0
- package/dist/loader.js.map +1 -0
- package/dist/next-env-compat.js +17735 -102
- package/dist/next-env-compat.js.map +1 -1
- package/dist/plugin.js +434 -141
- package/dist/plugin.js.map +1 -1
- package/package.json +16 -16
- package/LICENSE +0 -21
- package/dist/patch-next-runtime.js +0 -14
- package/dist/patch-next-runtime.js.map +0 -1
- /package/dist/{patch-next-runtime.d.ts → loader.d.ts} +0 -0
package/dist/plugin.js
CHANGED
|
@@ -1,15 +1,239 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
3
|
+
var fs3 = require('fs');
|
|
4
|
+
var path2 = require('path');
|
|
5
5
|
var env = require('varlock/env');
|
|
6
|
-
var patchServerResponse = require('varlock/patch-server-response');
|
|
7
6
|
var patchConsole = require('varlock/patch-console');
|
|
7
|
+
var patchServerResponse = require('varlock/patch-server-response');
|
|
8
|
+
require('varlock');
|
|
8
9
|
|
|
9
10
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
11
|
|
|
11
|
-
var
|
|
12
|
-
var
|
|
12
|
+
var fs3__default = /*#__PURE__*/_interopDefault(fs3);
|
|
13
|
+
var path2__default = /*#__PURE__*/_interopDefault(path2);
|
|
14
|
+
|
|
15
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
16
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
17
|
+
}) : x)(function(x) {
|
|
18
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
19
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
20
|
+
});
|
|
21
|
+
var WEBPACK_PLUGIN_NAME = "VarlockNextWebpackPlugin";
|
|
22
|
+
var latestLoadedVarlockEnv;
|
|
23
|
+
function createStaticReplacementsProxy(debug3) {
|
|
24
|
+
return new Proxy({}, {
|
|
25
|
+
ownKeys(_target) {
|
|
26
|
+
latestLoadedVarlockEnv = JSON.parse(process.env.__VARLOCK_ENV || "{}");
|
|
27
|
+
const replaceKeys = [];
|
|
28
|
+
for (const itemKey in latestLoadedVarlockEnv.config) {
|
|
29
|
+
const item = latestLoadedVarlockEnv.config[itemKey];
|
|
30
|
+
if (!item.isSensitive) replaceKeys.push(`ENV.${itemKey}`);
|
|
31
|
+
}
|
|
32
|
+
debug3("reloaded static replacements keys", replaceKeys);
|
|
33
|
+
return replaceKeys;
|
|
34
|
+
},
|
|
35
|
+
getOwnPropertyDescriptor(_target, prop) {
|
|
36
|
+
const itemKey = prop.toString().split(".")[1];
|
|
37
|
+
const item = latestLoadedVarlockEnv?.config[itemKey];
|
|
38
|
+
if (!item || item.isSensitive) return;
|
|
39
|
+
return {
|
|
40
|
+
value: "",
|
|
41
|
+
// this value is not used, the get handler will return the value
|
|
42
|
+
writable: false,
|
|
43
|
+
enumerable: true,
|
|
44
|
+
configurable: true
|
|
45
|
+
};
|
|
46
|
+
},
|
|
47
|
+
get(_target, prop) {
|
|
48
|
+
const itemKey = prop.toString().split(".")[1];
|
|
49
|
+
const item = latestLoadedVarlockEnv?.config[itemKey];
|
|
50
|
+
if (item && !item.isSensitive) return JSON.stringify(item.value);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
function createWebpackConfigFn(resolvedNextConfig, patchGlobalFsMethods2, debug3, isBuild) {
|
|
55
|
+
const staticReplacementsProxy = createStaticReplacementsProxy(debug3);
|
|
56
|
+
return function webpackConfigFn(webpackConfig, options) {
|
|
57
|
+
debug3("varlockNextConfigPlugin webpack config patching");
|
|
58
|
+
const { dev } = options;
|
|
59
|
+
if (isBuild) patchGlobalFsMethods2();
|
|
60
|
+
if (env.varlockSettings.preventLeaks) {
|
|
61
|
+
patchServerResponse.patchGlobalServerResponse({
|
|
62
|
+
ignoreUrlPatterns: [
|
|
63
|
+
/^\/__nextjs_source-map\?.*/,
|
|
64
|
+
// sourcemaps
|
|
65
|
+
/[?&]_rsc=/
|
|
66
|
+
// RSC payloads are server-side and expected to contain sensitive data
|
|
67
|
+
],
|
|
68
|
+
// in dev mode, we redact the secrets rather than throwing, because otherwise the dev server crashes
|
|
69
|
+
redactInsteadOfThrow: dev
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
const webpack = options.webpack;
|
|
73
|
+
if (resolvedNextConfig.webpack) {
|
|
74
|
+
webpackConfig = resolvedNextConfig.webpack(webpackConfig, options);
|
|
75
|
+
}
|
|
76
|
+
if (!process.env.__VARLOCK_ENV) throw new Error("VarlockNextWebpackPlugin: __VARLOCK_ENV is not set");
|
|
77
|
+
if (options.isServer && options.nextRuntime !== "edge") {
|
|
78
|
+
webpackConfig.module.rules.push({
|
|
79
|
+
test: /\.(js|jsx|ts|tsx|mjs|mts)$/,
|
|
80
|
+
exclude: /node_modules/,
|
|
81
|
+
use: [
|
|
82
|
+
{
|
|
83
|
+
loader: __require.resolve("./loader"),
|
|
84
|
+
options: { bundler: "webpack" }
|
|
85
|
+
}
|
|
86
|
+
]
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
if (options.isServer && options.nextRuntime === "edge") {
|
|
90
|
+
webpackConfig.module.rules.push({
|
|
91
|
+
test: /\.(js|jsx|ts|tsx|mjs|mts)$/,
|
|
92
|
+
exclude: /node_modules/,
|
|
93
|
+
use: [
|
|
94
|
+
{
|
|
95
|
+
loader: __require.resolve("./loader"),
|
|
96
|
+
options: { bundler: "webpack", isEdge: true }
|
|
97
|
+
}
|
|
98
|
+
]
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
debug3("adding ENV.xxx static replacements proxy object");
|
|
102
|
+
webpackConfig.plugins.push(new webpack.DefinePlugin(staticReplacementsProxy));
|
|
103
|
+
if (env.varlockSettings.preventLeaks) {
|
|
104
|
+
webpackConfig.plugins.push({
|
|
105
|
+
apply(compiler) {
|
|
106
|
+
compiler.hooks.assetEmitted.tap(WEBPACK_PLUGIN_NAME, (_file, assetDetails) => {
|
|
107
|
+
const { content, targetPath } = assetDetails;
|
|
108
|
+
if (targetPath.includes("/.next/static/chunks/") || targetPath.endsWith(".html")) {
|
|
109
|
+
try {
|
|
110
|
+
env.scanForLeaks(content, {
|
|
111
|
+
method: "@varlock/nextjs-integration/plugin - assetEmitted hook",
|
|
112
|
+
file: targetPath
|
|
113
|
+
});
|
|
114
|
+
} catch (err) {
|
|
115
|
+
if (dev) {
|
|
116
|
+
fs3__default.default.writeFileSync(targetPath, env.redactSensitiveConfig(content.toString()));
|
|
117
|
+
} else {
|
|
118
|
+
throw err;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
function injectVarlockInitIntoWebpackRuntime(edgeRuntime = false) {
|
|
127
|
+
return function assetUpdateFn(origSource) {
|
|
128
|
+
const origSourceStr = origSource.source();
|
|
129
|
+
const initBundleName = edgeRuntime ? "init-edge" : "init-server";
|
|
130
|
+
const injectorPath = __require.resolve(`varlock/${initBundleName}`);
|
|
131
|
+
const injectorSrc = fs3__default.default.readFileSync(injectorPath, "utf8");
|
|
132
|
+
const rawEnv = process.env.__VARLOCK_ENV;
|
|
133
|
+
const envInline = rawEnv ? `process.env.__VARLOCK_ENV = process.env.__VARLOCK_ENV || ${JSON.stringify(rawEnv)};` : "";
|
|
134
|
+
const updatedSourceStr = [
|
|
135
|
+
envInline,
|
|
136
|
+
// Wrap in IIFE to avoid symbol collisions when bundlers concatenate files.
|
|
137
|
+
// Provide dummy exports/module since the CJS bundle uses `exports.X = ...`
|
|
138
|
+
`(function(exports,module){${injectorSrc}})({},{exports:{}});`,
|
|
139
|
+
origSourceStr
|
|
140
|
+
].join("\n");
|
|
141
|
+
return new webpack.sources.RawSource(updatedSourceStr);
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
const isEdgeRuntime = options.nextRuntime === "edge";
|
|
145
|
+
webpackConfig.plugins.push({
|
|
146
|
+
apply(compiler) {
|
|
147
|
+
compiler.hooks.thisCompilation.tap(WEBPACK_PLUGIN_NAME, (compilation) => {
|
|
148
|
+
compilation.hooks.processAssets.tap(
|
|
149
|
+
{
|
|
150
|
+
name: WEBPACK_PLUGIN_NAME,
|
|
151
|
+
stage: webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONS
|
|
152
|
+
},
|
|
153
|
+
() => {
|
|
154
|
+
if (isEdgeRuntime) {
|
|
155
|
+
if (compilation.getAsset("edge-runtime-webpack.js")) {
|
|
156
|
+
compilation.updateAsset("edge-runtime-webpack.js", injectVarlockInitIntoWebpackRuntime(true));
|
|
157
|
+
}
|
|
158
|
+
for (const name of ["webpack-runtime.js", "../webpack-runtime.js"]) {
|
|
159
|
+
if (compilation.getAsset(name)) {
|
|
160
|
+
compilation.updateAsset(name, injectVarlockInitIntoWebpackRuntime(true));
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
} else if (options.isServer) {
|
|
164
|
+
for (const name of ["webpack-runtime.js", "../webpack-runtime.js", "webpack-api-runtime.js", "../webpack-api-runtime.js"]) {
|
|
165
|
+
if (compilation.getAsset(name)) {
|
|
166
|
+
compilation.updateAsset(name, injectVarlockInitIntoWebpackRuntime());
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
);
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
return webpackConfig;
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
function debug(...args) {
|
|
179
|
+
if (!process.env.DEBUG_VARLOCK_NEXT_INTEGRATION) return;
|
|
180
|
+
console.log("[varlock]", ...args);
|
|
181
|
+
}
|
|
182
|
+
var injectedTurbopackRuntime = false;
|
|
183
|
+
function injectVarlockInitIntoTurbopackRuntime(nextDirPath) {
|
|
184
|
+
if (injectedTurbopackRuntime) return;
|
|
185
|
+
const rawEnv = process.env.__VARLOCK_ENV;
|
|
186
|
+
if (!rawEnv) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
const serverRuntimeFiles = [];
|
|
190
|
+
const edgeWrapperFiles = [];
|
|
191
|
+
const walkDir = (dir) => {
|
|
192
|
+
if (!fs3__default.default.existsSync(dir)) return;
|
|
193
|
+
for (const entry of fs3__default.default.readdirSync(dir, { withFileTypes: true })) {
|
|
194
|
+
if (entry.isDirectory()) {
|
|
195
|
+
walkDir(path2__default.default.join(dir, entry.name));
|
|
196
|
+
} else if (entry.name === "[turbopack]_runtime.js") {
|
|
197
|
+
serverRuntimeFiles.push(path2__default.default.join(dir, entry.name));
|
|
198
|
+
} else if (entry.name.includes("edge-wrapper") && entry.name.endsWith(".js")) {
|
|
199
|
+
edgeWrapperFiles.push(path2__default.default.join(dir, entry.name));
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
walkDir(nextDirPath);
|
|
204
|
+
debug(`turbopack runtime injection: found ${serverRuntimeFiles.length} server runtime files, ${edgeWrapperFiles.length} edge wrapper files`);
|
|
205
|
+
if (!serverRuntimeFiles.length) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
injectedTurbopackRuntime = true;
|
|
209
|
+
const initServerSrc = fs3__default.default.readFileSync(__require.resolve("varlock/init-server"), "utf8");
|
|
210
|
+
const initEdgeSrc = fs3__default.default.readFileSync(__require.resolve("varlock/init-edge"), "utf8");
|
|
211
|
+
const envInline = `process.env.__VARLOCK_ENV = process.env.__VARLOCK_ENV || ${JSON.stringify(rawEnv)};`;
|
|
212
|
+
const iifeWrap = (src) => `(function(exports,module){${src}})({},{exports:{}});`;
|
|
213
|
+
for (const runtimeFile of serverRuntimeFiles) {
|
|
214
|
+
const origSource = fs3__default.default.readFileSync(runtimeFile, "utf8");
|
|
215
|
+
const updatedSource = [
|
|
216
|
+
envInline,
|
|
217
|
+
iifeWrap(initServerSrc),
|
|
218
|
+
origSource
|
|
219
|
+
].join("\n");
|
|
220
|
+
fs3__default.default.writeFileSync(runtimeFile, updatedSource);
|
|
221
|
+
debug(`injected init-server into turbopack runtime: ${runtimeFile}`);
|
|
222
|
+
}
|
|
223
|
+
for (const wrapperFile of edgeWrapperFiles) {
|
|
224
|
+
const origSource = fs3__default.default.readFileSync(wrapperFile, "utf8");
|
|
225
|
+
const updatedSource = [
|
|
226
|
+
envInline,
|
|
227
|
+
iifeWrap(initEdgeSrc),
|
|
228
|
+
origSource
|
|
229
|
+
].join("\n");
|
|
230
|
+
fs3__default.default.writeFileSync(wrapperFile, updatedSource);
|
|
231
|
+
debug(`injected init-edge into edge wrapper: ${wrapperFile}`);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
function isInjectedTurbopackRuntime() {
|
|
235
|
+
return injectedTurbopackRuntime;
|
|
236
|
+
}
|
|
13
237
|
|
|
14
238
|
// src/plugin.ts
|
|
15
239
|
if (!process.env.__VARLOCK_ENV) {
|
|
@@ -23,8 +247,21 @@ if (!process.env.__VARLOCK_ENV) {
|
|
|
23
247
|
throw new Error("VarlockNextWebpackPlugin: __VARLOCK_ENV is not set");
|
|
24
248
|
}
|
|
25
249
|
patchConsole.patchGlobalConsole();
|
|
250
|
+
var IS_TURBOPACK = !!(process.env.TURBOPACK || process.env.TURBOPACK_DEV || process.env.TURBOPACK_BUILD || process.env.npm_config_turbopack);
|
|
251
|
+
if (IS_TURBOPACK && env.varlockSettings.preventLeaks) {
|
|
252
|
+
patchServerResponse.patchGlobalServerResponse({
|
|
253
|
+
ignoreUrlPatterns: [
|
|
254
|
+
/^\/__nextjs_source-map\?.*/,
|
|
255
|
+
// sourcemaps
|
|
256
|
+
/[?&]_rsc=/
|
|
257
|
+
// RSC payloads are server-side and expected to contain sensitive data
|
|
258
|
+
],
|
|
259
|
+
// always redact in dev to avoid crashing the dev server; prod builds override via init bundles
|
|
260
|
+
redactInsteadOfThrow: true
|
|
261
|
+
});
|
|
262
|
+
}
|
|
26
263
|
var IS_WORKER = !!process.env.NEXT_PRIVATE_WORKER;
|
|
27
|
-
function
|
|
264
|
+
function debug2(...args) {
|
|
28
265
|
if (!process.env.DEBUG_VARLOCK_NEXT_INTEGRATION) return;
|
|
29
266
|
console.log(
|
|
30
267
|
"plugin",
|
|
@@ -33,60 +270,148 @@ function debug(...args) {
|
|
|
33
270
|
...args
|
|
34
271
|
);
|
|
35
272
|
}
|
|
36
|
-
|
|
37
|
-
var WEBPACK_PLUGIN_NAME = "VarlockNextWebpackPlugin";
|
|
273
|
+
debug2("\u2728 LOADED @varlock/next-integration/plugin module!");
|
|
38
274
|
var scannedStaticFiles = false;
|
|
39
275
|
async function scanStaticFiles(nextDirPath) {
|
|
40
276
|
scannedStaticFiles = true;
|
|
41
|
-
for await (const file of
|
|
42
|
-
const fileContents = await
|
|
277
|
+
for await (const file of fs3__default.default.promises.glob(`${nextDirPath}/**/*.html`)) {
|
|
278
|
+
const fileContents = await fs3__default.default.promises.readFile(file, "utf8");
|
|
43
279
|
env.scanForLeaks(fileContents, { method: "nextjs scan static html files", file });
|
|
44
280
|
}
|
|
45
281
|
}
|
|
282
|
+
var scrubbedSourcemaps = false;
|
|
283
|
+
async function scrubSourcemaps(nextDirPath) {
|
|
284
|
+
if (scrubbedSourcemaps) return;
|
|
285
|
+
scrubbedSourcemaps = true;
|
|
286
|
+
const envGraph = JSON.parse(process.env.__VARLOCK_ENV || "{}");
|
|
287
|
+
const sensitiveValues = [];
|
|
288
|
+
for (const itemKey in envGraph.config) {
|
|
289
|
+
const item = envGraph.config[itemKey];
|
|
290
|
+
if (item.isSensitive && item.value && typeof item.value === "string" && item.value.length > 0) {
|
|
291
|
+
sensitiveValues.push({
|
|
292
|
+
value: item.value,
|
|
293
|
+
replacement: "*".repeat(item.value.length)
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
if (!sensitiveValues.length) {
|
|
298
|
+
debug2("no sensitive values to scrub from sourcemaps");
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
sensitiveValues.sort((a, b) => b.value.length - a.value.length);
|
|
302
|
+
let scrubCount = 0;
|
|
303
|
+
for await (const mapFile of fs3__default.default.promises.glob(`${nextDirPath}/**/*.map`)) {
|
|
304
|
+
const contents = await fs3__default.default.promises.readFile(mapFile, "utf8");
|
|
305
|
+
let scrubbed = contents;
|
|
306
|
+
for (const { value, replacement } of sensitiveValues) {
|
|
307
|
+
scrubbed = scrubbed.replaceAll(value, replacement);
|
|
308
|
+
}
|
|
309
|
+
if (scrubbed !== contents) {
|
|
310
|
+
await fs3__default.default.promises.writeFile(mapFile, scrubbed);
|
|
311
|
+
scrubCount++;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
debug2(`scrubbed sensitive values from ${scrubCount} sourcemap files`);
|
|
315
|
+
}
|
|
316
|
+
var scannedBuildOutput = false;
|
|
317
|
+
async function scanBuildOutputForLeaks(nextDirPath, opts) {
|
|
318
|
+
if (scannedBuildOutput) return;
|
|
319
|
+
scannedBuildOutput = true;
|
|
320
|
+
let preventLeaks = env.varlockSettings.preventLeaks;
|
|
321
|
+
if (preventLeaks === void 0 && process.env.__VARLOCK_ENV) {
|
|
322
|
+
try {
|
|
323
|
+
const envGraph = JSON.parse(process.env.__VARLOCK_ENV);
|
|
324
|
+
preventLeaks = envGraph.settings?.preventLeaks;
|
|
325
|
+
} catch {
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
if (process.env.__VARLOCK_ENV) {
|
|
329
|
+
try {
|
|
330
|
+
env.initVarlockEnv();
|
|
331
|
+
} catch {
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
const redactionInfo = env.getRedactionMapInfo();
|
|
335
|
+
debug2(`scanBuildOutputForLeaks: preventLeaks=${preventLeaks}, redactionInfo=${JSON.stringify(redactionInfo)}`);
|
|
336
|
+
if (!preventLeaks) return;
|
|
337
|
+
const leakedFiles = [];
|
|
338
|
+
let scannedCount = 0;
|
|
339
|
+
for await (const file of fs3__default.default.promises.glob(`${nextDirPath}/static/chunks/**/*.js`)) {
|
|
340
|
+
scannedCount++;
|
|
341
|
+
const fileContents = await fs3__default.default.promises.readFile(file, "utf8");
|
|
342
|
+
try {
|
|
343
|
+
env.scanForLeaks(fileContents, {
|
|
344
|
+
method: "nextjs post-build scan (static chunks)",
|
|
345
|
+
file
|
|
346
|
+
});
|
|
347
|
+
} catch (err) {
|
|
348
|
+
leakedFiles.push(file);
|
|
349
|
+
await fs3__default.default.promises.writeFile(file, env.redactSensitiveConfig(fileContents));
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
debug2(`scanned ${scannedCount} static chunk files in ${nextDirPath}/static/chunks/`);
|
|
353
|
+
for (const ext of ["html"]) {
|
|
354
|
+
for await (const file of fs3__default.default.promises.glob(`${nextDirPath}/**/*.${ext}`)) {
|
|
355
|
+
scannedCount++;
|
|
356
|
+
const fileContents = await fs3__default.default.promises.readFile(file, "utf8");
|
|
357
|
+
try {
|
|
358
|
+
env.scanForLeaks(fileContents, {
|
|
359
|
+
method: `nextjs post-build scan (.${ext})`,
|
|
360
|
+
file
|
|
361
|
+
});
|
|
362
|
+
} catch (err) {
|
|
363
|
+
leakedFiles.push(file);
|
|
364
|
+
await fs3__default.default.promises.writeFile(file, env.redactSensitiveConfig(fileContents));
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
debug2(`scanned ${scannedCount} total build output files`);
|
|
369
|
+
if (leakedFiles.length > 0) {
|
|
370
|
+
const msg = `[varlock] \u26A0\uFE0F found and redacted leaked secrets in ${leakedFiles.length} build output file(s):
|
|
371
|
+
${leakedFiles.map((f) => ` - ${f}`).join("\n")}`;
|
|
372
|
+
if (opts?.failBuild) {
|
|
373
|
+
throw new Error(msg);
|
|
374
|
+
}
|
|
375
|
+
console.error(msg);
|
|
376
|
+
} else {
|
|
377
|
+
debug2("\u2705 no leaks found in build output");
|
|
378
|
+
}
|
|
379
|
+
}
|
|
46
380
|
function patchGlobalFsMethods() {
|
|
47
|
-
|
|
48
|
-
|
|
381
|
+
debug2("patching global fs methods");
|
|
382
|
+
const origWriteFileFn = fs3__default.default.promises.writeFile;
|
|
383
|
+
fs3__default.default.promises.writeFile = async function dmnoPatchedWriteFile(...args) {
|
|
49
384
|
const filePath = args[0].toString();
|
|
385
|
+
debug2("fs.promises.writeFile:", filePath);
|
|
386
|
+
if (!isInjectedTurbopackRuntime() && filePath.endsWith("/.next/export-detail.json")) {
|
|
387
|
+
const nextDirPath = filePath.substring(0, filePath.lastIndexOf("/"));
|
|
388
|
+
injectVarlockInitIntoTurbopackRuntime(nextDirPath);
|
|
389
|
+
}
|
|
50
390
|
if (filePath.endsWith("/.next/next-server.js.nft.json") && !scannedStaticFiles) {
|
|
51
391
|
const nextDirPath = filePath.substring(0, filePath.lastIndexOf("/"));
|
|
52
392
|
await scanStaticFiles(nextDirPath);
|
|
53
393
|
}
|
|
394
|
+
if (filePath.endsWith("/.next/next-server.js.nft.json") || filePath.endsWith("/.next/prerender-manifest.json")) {
|
|
395
|
+
const nextDirPath = filePath.substring(0, filePath.lastIndexOf("/"));
|
|
396
|
+
if (!scrubbedSourcemaps) await scrubSourcemaps(nextDirPath);
|
|
397
|
+
if (!scannedBuildOutput) await scanBuildOutputForLeaks(nextDirPath, { failBuild: true });
|
|
398
|
+
}
|
|
54
399
|
return origWriteFileFn.call(this, ...args);
|
|
55
400
|
};
|
|
401
|
+
const origWriteFileSyncFn = fs3__default.default.writeFileSync;
|
|
402
|
+
fs3__default.default.writeFileSync = function dmnoPatchedWriteFileSync(...args) {
|
|
403
|
+
const filePath = args[0].toString();
|
|
404
|
+
debug2("fs.writeFileSync:", filePath);
|
|
405
|
+
if (!isInjectedTurbopackRuntime() && filePath.endsWith("/.next/diagnostics/build-diagnostics.json")) {
|
|
406
|
+
const nextDirPath = filePath.substring(0, filePath.lastIndexOf("/"));
|
|
407
|
+
injectVarlockInitIntoTurbopackRuntime(nextDirPath);
|
|
408
|
+
}
|
|
409
|
+
return origWriteFileSyncFn.call(this, ...args);
|
|
410
|
+
};
|
|
56
411
|
}
|
|
57
|
-
var latestLoadedVarlockEnv;
|
|
58
|
-
var StaticReplacementsProxy = new Proxy({}, {
|
|
59
|
-
ownKeys(_target) {
|
|
60
|
-
latestLoadedVarlockEnv = JSON.parse(process.env.__VARLOCK_ENV || "{}");
|
|
61
|
-
const replaceKeys = [];
|
|
62
|
-
for (const itemKey in latestLoadedVarlockEnv.config) {
|
|
63
|
-
const item = latestLoadedVarlockEnv.config[itemKey];
|
|
64
|
-
if (!item.isSensitive) replaceKeys.push(`ENV.${itemKey}`);
|
|
65
|
-
}
|
|
66
|
-
debug("reloaded static replacements keys", replaceKeys);
|
|
67
|
-
return replaceKeys;
|
|
68
|
-
},
|
|
69
|
-
getOwnPropertyDescriptor(_target, prop) {
|
|
70
|
-
const itemKey = prop.toString().split(".")[1];
|
|
71
|
-
const item = latestLoadedVarlockEnv?.config[itemKey];
|
|
72
|
-
if (!item || item.isSensitive) return;
|
|
73
|
-
return {
|
|
74
|
-
value: "",
|
|
75
|
-
// this value is not used, the get handler will return the value
|
|
76
|
-
writable: false,
|
|
77
|
-
enumerable: true,
|
|
78
|
-
configurable: true
|
|
79
|
-
};
|
|
80
|
-
},
|
|
81
|
-
get(_target, prop) {
|
|
82
|
-
const itemKey = prop.toString().split(".")[1];
|
|
83
|
-
const item = latestLoadedVarlockEnv?.config[itemKey];
|
|
84
|
-
if (item && !item.isSensitive) return JSON.stringify(item.value);
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
412
|
function varlockNextConfigPlugin(_pluginOptions) {
|
|
88
413
|
return (nextConfig) => {
|
|
89
|
-
|
|
414
|
+
debug2("varlockNextConfigPlugin init fn");
|
|
90
415
|
return async (phase, defaults) => {
|
|
91
416
|
let resolvedNextConfig;
|
|
92
417
|
if (typeof nextConfig === "function") {
|
|
@@ -95,107 +420,75 @@ function varlockNextConfigPlugin(_pluginOptions) {
|
|
|
95
420
|
} else {
|
|
96
421
|
resolvedNextConfig = nextConfig;
|
|
97
422
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
webpack(webpackConfig, options) {
|
|
112
|
-
debug("varlockNextConfigPlugin webpack config patching");
|
|
113
|
-
const { dev } = options;
|
|
114
|
-
if (env.varlockSettings.preventLeaks) {
|
|
115
|
-
patchGlobalFsMethods();
|
|
116
|
-
patchServerResponse.patchGlobalServerResponse({
|
|
117
|
-
// ignore sourcemaps - although we may in future want to scrub them?
|
|
118
|
-
ignoreUrlPatterns: [/^\/__nextjs_source-map\?.*/],
|
|
119
|
-
// in dev mode, we redact the secrets rather than throwing, because otherwise the dev server crashes
|
|
120
|
-
redactInsteadOfThrow: dev
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
const webpack = options.webpack;
|
|
124
|
-
if (resolvedNextConfig.webpack) {
|
|
125
|
-
webpackConfig = resolvedNextConfig.webpack(webpackConfig, options);
|
|
126
|
-
}
|
|
127
|
-
if (!process.env.__VARLOCK_ENV) throw new Error("VarlockNextWebpackPlugin: __VARLOCK_ENV is not set");
|
|
128
|
-
debug("adding ENV.xxx static replacements proxy object");
|
|
129
|
-
webpackConfig.plugins.push(new webpack.DefinePlugin(StaticReplacementsProxy));
|
|
130
|
-
if (env.varlockSettings.preventLeaks) {
|
|
131
|
-
webpackConfig.plugins.push({
|
|
132
|
-
apply(compiler) {
|
|
133
|
-
compiler.hooks.assetEmitted.tap(WEBPACK_PLUGIN_NAME, (file, assetDetails) => {
|
|
134
|
-
const { content, targetPath } = assetDetails;
|
|
135
|
-
if (targetPath.includes("/.next/static/chunks/") || targetPath.endsWith(".html") || targetPath.endsWith(".body") || targetPath.endsWith(".rsc")) {
|
|
136
|
-
try {
|
|
137
|
-
env.scanForLeaks(content, {
|
|
138
|
-
method: "@varlock/nextjs-integration/plugin - assetEmitted hook",
|
|
139
|
-
file: targetPath
|
|
140
|
-
});
|
|
141
|
-
} catch (err) {
|
|
142
|
-
if (dev) {
|
|
143
|
-
fs__default.default.writeFileSync(targetPath, env.redactSensitiveConfig(content.toString()));
|
|
144
|
-
} else {
|
|
145
|
-
throw err;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
});
|
|
150
|
-
}
|
|
423
|
+
const isTurbopack = !!(process.env.TURBOPACK || process.env.TURBOPACK_DEV || process.env.TURBOPACK_BUILD || process.env.npm_config_turbopack);
|
|
424
|
+
const isBuild = phase === "phase-production-build";
|
|
425
|
+
debug2(`turbopack detection: TURBOPACK=${process.env.TURBOPACK}, TURBOPACK_DEV=${process.env.TURBOPACK_DEV}, TURBOPACK_BUILD=${process.env.TURBOPACK_BUILD}, phase=${phase}, isTurbopack=${isTurbopack}, isBuild=${isBuild}`);
|
|
426
|
+
if (isBuild) {
|
|
427
|
+
process.once("beforeExit", () => {
|
|
428
|
+
const nextDirPath = path2__default.default.resolve(process.cwd(), ".next");
|
|
429
|
+
const scanPromises = [];
|
|
430
|
+
if (!scrubbedSourcemaps) scanPromises.push(scrubSourcemaps(nextDirPath));
|
|
431
|
+
if (!scannedBuildOutput) scanPromises.push(scanBuildOutputForLeaks(nextDirPath, { failBuild: true }));
|
|
432
|
+
if (scanPromises.length > 0) {
|
|
433
|
+
Promise.all(scanPromises).catch((err) => {
|
|
434
|
+
console.error("[varlock] post-build scan failed:", err);
|
|
435
|
+
process.exitCode = 1;
|
|
151
436
|
});
|
|
152
437
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
if (isTurbopack) {
|
|
441
|
+
debug2("turbopack detected, injecting loader rules");
|
|
442
|
+
if (isBuild) patchGlobalFsMethods();
|
|
443
|
+
let turbopackConfig = resolvedNextConfig.turbopack ?? resolvedNextConfig.experimental?.turbo;
|
|
444
|
+
if (!turbopackConfig) {
|
|
445
|
+
turbopackConfig = {};
|
|
446
|
+
resolvedNextConfig.turbopack = turbopackConfig;
|
|
447
|
+
}
|
|
448
|
+
const loaderRule = {
|
|
449
|
+
loaders: [__require.resolve("./loader")]
|
|
450
|
+
};
|
|
451
|
+
turbopackConfig.rules ||= {};
|
|
452
|
+
turbopackConfig.rules["*.{js,jsx,ts,tsx,mjs,mts}"] = loaderRule;
|
|
453
|
+
const varlockNodeModulesPath = path2__default.default.resolve(process.cwd(), "node_modules/varlock");
|
|
454
|
+
let isSymlinked = false;
|
|
455
|
+
try {
|
|
456
|
+
isSymlinked = fs3__default.default.lstatSync(varlockNodeModulesPath).isSymbolicLink();
|
|
457
|
+
} catch {
|
|
458
|
+
}
|
|
459
|
+
if (isSymlinked) {
|
|
460
|
+
debug2("varlock is symlinked, copying dist files for turbopack");
|
|
461
|
+
const varlockDistDir = path2__default.default.resolve(path2__default.default.dirname(__require.resolve("varlock/env")), "..");
|
|
462
|
+
const varlockRoot = path2__default.default.resolve(varlockDistDir, "..");
|
|
463
|
+
const cacheDir = path2__default.default.resolve(process.cwd(), "node_modules/.varlock");
|
|
464
|
+
const cacheDistDir = path2__default.default.join(cacheDir, "dist");
|
|
465
|
+
try {
|
|
466
|
+
fs3__default.default.mkdirSync(cacheDir, { recursive: true });
|
|
467
|
+
fs3__default.default.cpSync(varlockDistDir, cacheDistDir, { recursive: true });
|
|
468
|
+
fs3__default.default.copyFileSync(path2__default.default.join(varlockRoot, "package.json"), path2__default.default.join(cacheDir, "package.json"));
|
|
469
|
+
debug2("copied varlock package files to", cacheDir);
|
|
470
|
+
} catch (err) {
|
|
471
|
+
console.warn("[varlock] failed to copy varlock package files:", err);
|
|
168
472
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
compilation.updateAsset("../webpack-api-runtime.js", injectVarlockInitIntoWebpackRuntime());
|
|
189
|
-
}
|
|
190
|
-
if (compilation.getAsset("edge-runtime-webpack.js")) {
|
|
191
|
-
compilation.updateAsset("edge-runtime-webpack.js", injectVarlockInitIntoWebpackRuntime(true));
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
);
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
});
|
|
198
|
-
return webpackConfig;
|
|
473
|
+
turbopackConfig.resolveAlias ||= {};
|
|
474
|
+
turbopackConfig.resolveAlias["varlock/env"] = "./node_modules/.varlock/dist/runtime/env.js";
|
|
475
|
+
turbopackConfig.resolveAlias["varlock/patch-console"] = "./node_modules/.varlock/dist/runtime/patch-console.js";
|
|
476
|
+
turbopackConfig.resolveAlias["varlock/patch-server-response"] = "./node_modules/.varlock/dist/runtime/patch-server-response.js";
|
|
477
|
+
turbopackConfig.resolveAlias["varlock/patch-response"] = "./node_modules/.varlock/dist/runtime/patch-response.js";
|
|
478
|
+
turbopackConfig.resolveAlias["varlock/init-server"] = "./node_modules/.varlock/dist/runtime/init-server.cjs";
|
|
479
|
+
turbopackConfig.resolveAlias["varlock/init-edge"] = "./node_modules/.varlock/dist/runtime/init-edge.cjs";
|
|
480
|
+
debug2("set resolveAlias for varlock subpaths -> ./node_modules/.varlock/dist/...");
|
|
481
|
+
} else {
|
|
482
|
+
debug2("varlock is not symlinked, turbopack can resolve it natively");
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
return {
|
|
486
|
+
...resolvedNextConfig,
|
|
487
|
+
...isTurbopack && {
|
|
488
|
+
turbopack: resolvedNextConfig.turbopack
|
|
489
|
+
},
|
|
490
|
+
...!IS_TURBOPACK && {
|
|
491
|
+
webpack: createWebpackConfigFn(resolvedNextConfig, patchGlobalFsMethods, debug2, isBuild)
|
|
199
492
|
}
|
|
200
493
|
};
|
|
201
494
|
};
|