@zuplo/cli 7.6.6 → 7.6.8
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/dist/__tests__/populate.test.js +104 -28
- package/dist/__tests__/populate.test.js.map +1 -1
- package/dist/common/populate.d.ts.map +1 -1
- package/dist/common/populate.js +46 -10
- package/dist/common/populate.js.map +1 -1
- package/node_modules/@inquirer/ansi/package.json +3 -2
- package/node_modules/@inquirer/checkbox/package.json +6 -6
- package/node_modules/@inquirer/confirm/package.json +4 -4
- package/node_modules/@inquirer/core/package.json +5 -5
- package/node_modules/@inquirer/editor/package.json +5 -5
- package/node_modules/@inquirer/expand/package.json +4 -4
- package/node_modules/@inquirer/external-editor/package.json +2 -2
- package/node_modules/@inquirer/figures/package.json +2 -2
- package/node_modules/@inquirer/input/package.json +4 -4
- package/node_modules/@inquirer/number/package.json +4 -4
- package/node_modules/@inquirer/password/package.json +5 -5
- package/node_modules/@inquirer/rawlist/package.json +4 -4
- package/node_modules/@inquirer/search/package.json +5 -5
- package/node_modules/@inquirer/select/package.json +6 -6
- package/node_modules/@inquirer/type/package.json +2 -2
- package/node_modules/@posthog/types/dist/posthog-config.d.ts +11 -0
- package/node_modules/@posthog/types/dist/posthog-config.d.ts.map +1 -1
- package/node_modules/@posthog/types/package.json +3 -3
- package/node_modules/@posthog/types/src/posthog-config.ts +9 -0
- package/node_modules/@zuplo/core/package.json +1 -1
- package/node_modules/@zuplo/graphql/package.json +1 -1
- package/node_modules/@zuplo/openapi-tools/package.json +1 -1
- package/node_modules/@zuplo/otel/package.json +1 -1
- package/node_modules/@zuplo/runtime/out/esm/{chunk-VXNLSYUR.js → chunk-ZZCZZHOD.js} +3 -3
- package/node_modules/@zuplo/runtime/out/esm/{chunk-VXNLSYUR.js.map → chunk-ZZCZZHOD.js.map} +1 -1
- package/node_modules/@zuplo/runtime/out/esm/index.js +1 -1
- package/node_modules/@zuplo/runtime/out/esm/mcp-gateway/index.js +1 -1
- package/node_modules/@zuplo/runtime/out/types/index.d.ts +14 -14
- package/node_modules/@zuplo/runtime/package.json +1 -1
- package/node_modules/fast-copy/README.md +3 -2
- package/node_modules/fast-copy/dist/cjs/index.cjs +19 -4
- package/node_modules/fast-copy/dist/cjs/index.cjs.map +1 -1
- package/node_modules/fast-copy/dist/es/index.mjs +19 -4
- package/node_modules/fast-copy/dist/es/index.mjs.map +1 -1
- package/node_modules/fast-copy/dist/umd/index.js +19 -4
- package/node_modules/fast-copy/dist/umd/index.js.map +1 -1
- package/node_modules/fast-copy/package.json +17 -16
- package/node_modules/fast-uri/index.js +20 -5
- package/node_modules/fast-uri/lib/utils.js +8 -1
- package/node_modules/fast-uri/package.json +1 -1
- package/node_modules/fast-uri/test/component-safe-serialization.test.js +58 -0
- package/node_modules/fast-uri/test/ipv6-validation.test.js +34 -0
- package/package.json +11 -11
- /package/node_modules/@zuplo/runtime/out/esm/{chunk-VXNLSYUR.js.LEGAL.txt → chunk-ZZCZZHOD.js.LEGAL.txt} +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { strict as nodeAssert } from "node:assert";
|
|
1
2
|
import { mkdtemp, readFile, rm } from "node:fs/promises";
|
|
2
3
|
import { tmpdir } from "node:os";
|
|
3
4
|
import { join } from "node:path";
|
|
@@ -8,6 +9,12 @@ import { getGlobalDispatcher, MockAgent, setGlobalDispatcher, } from "undici";
|
|
|
8
9
|
const TEST_ENVIRONMENT = "test-env-123";
|
|
9
10
|
const TEST_AUTH_TOKEN = "test-auth-token-456";
|
|
10
11
|
const TEST_API_ENDPOINT = "https://dev.zuplo.com";
|
|
12
|
+
const SYSTEM_PAYLOAD_KEYS = [
|
|
13
|
+
"accountName",
|
|
14
|
+
"projectName",
|
|
15
|
+
"environmentType",
|
|
16
|
+
"systemConfigurations",
|
|
17
|
+
];
|
|
11
18
|
describe("pullSystemConfig", () => {
|
|
12
19
|
let mockAgent;
|
|
13
20
|
let previousDispatcher;
|
|
@@ -220,14 +227,93 @@ describe("pullLocalConfig", () => {
|
|
|
220
227
|
const content = await readFile(envFilePath, "utf-8");
|
|
221
228
|
assert.include(content, 'DATABASE_URL="postgres://user:p@ssw0rd!@localhost:5432/db?ssl=true"');
|
|
222
229
|
assert.include(content, 'API_SECRET="secret-with-special-chars!@#$%^&*()"');
|
|
223
|
-
assert.include(content, 'JSON_CONFIG
|
|
230
|
+
assert.include(content, 'JSON_CONFIG=`{"key": "value", "nested": {"array": [1, 2, 3]}}`');
|
|
224
231
|
const userSectionRegex = /# Environment variables defined in the Zuplo UI[\s\S]*$/;
|
|
225
232
|
const userSection = content.match(userSectionRegex)?.[0] || "";
|
|
226
|
-
assert.include(userSection,
|
|
227
|
-
assert.include(userSection,
|
|
228
|
-
assert.include(userSection,
|
|
233
|
+
assert.include(userSection, "DATABASE_URL=");
|
|
234
|
+
assert.include(userSection, "API_SECRET=");
|
|
235
|
+
assert.include(userSection, "JSON_CONFIG=");
|
|
236
|
+
const parsedEnv = dotenvParse(content);
|
|
237
|
+
assert.equal(parsedEnv.DATABASE_URL, mockPayload.DATABASE_URL);
|
|
238
|
+
assert.equal(parsedEnv.API_SECRET, mockPayload.API_SECRET);
|
|
239
|
+
assert.equal(parsedEnv.JSON_CONFIG, mockPayload.JSON_CONFIG);
|
|
229
240
|
await rm(testDir, { recursive: true, force: true });
|
|
230
241
|
});
|
|
242
|
+
it("should preserve a Google service account JSON value", async () => {
|
|
243
|
+
const serviceAccount = {
|
|
244
|
+
type: "service_account",
|
|
245
|
+
project_id: "test-project",
|
|
246
|
+
private_key_id: "test-key-id",
|
|
247
|
+
private_key: "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASC\n-----END PRIVATE KEY-----\n",
|
|
248
|
+
client_email: "test-service-account@test-project.iam.gserviceaccount.com",
|
|
249
|
+
client_id: "1234567890",
|
|
250
|
+
auth_uri: "https://accounts.google.com/o/oauth2/auth",
|
|
251
|
+
token_uri: "https://oauth2.googleapis.com/token",
|
|
252
|
+
auth_provider_x509_cert_url: "https://www.googleapis.com/oauth2/v1/certs",
|
|
253
|
+
client_x509_cert_url: "https://www.googleapis.com/robot/v1/metadata/x509/test-service-account%40test-project.iam.gserviceaccount.com",
|
|
254
|
+
universe_domain: "googleapis.com",
|
|
255
|
+
};
|
|
256
|
+
const mockPayload = {
|
|
257
|
+
accountName: "test-account",
|
|
258
|
+
projectName: "test-project",
|
|
259
|
+
environmentType: "development",
|
|
260
|
+
systemConfigurations: "config-123",
|
|
261
|
+
GOOGLE_SERVICE_ACCOUNT: JSON.stringify(serviceAccount, null, 2),
|
|
262
|
+
};
|
|
263
|
+
mockAgent
|
|
264
|
+
.get(TEST_API_ENDPOINT)
|
|
265
|
+
.intercept({
|
|
266
|
+
path: `/v1/environments/${TEST_ENVIRONMENT}/local-configurations`,
|
|
267
|
+
method: "GET",
|
|
268
|
+
headers: {
|
|
269
|
+
authorization: `Bearer ${TEST_AUTH_TOKEN}`,
|
|
270
|
+
},
|
|
271
|
+
})
|
|
272
|
+
.reply(200, mockPayload);
|
|
273
|
+
const { pullLocalConfig } = await import("../common/populate.js");
|
|
274
|
+
await pullLocalConfig({
|
|
275
|
+
dir: testDir,
|
|
276
|
+
environment: TEST_ENVIRONMENT,
|
|
277
|
+
authToken: TEST_AUTH_TOKEN,
|
|
278
|
+
});
|
|
279
|
+
const content = await readFile(join(testDir, ".env.zuplo"), "utf-8");
|
|
280
|
+
assert.include(content, 'GOOGLE_SERVICE_ACCOUNT=`{\n "type": "service_account"');
|
|
281
|
+
const parsedEnv = dotenvParse(content);
|
|
282
|
+
assert.equal(parsedEnv.GOOGLE_SERVICE_ACCOUNT, mockPayload.GOOGLE_SERVICE_ACCOUNT);
|
|
283
|
+
assert.deepEqual(JSON.parse(parsedEnv.GOOGLE_SERVICE_ACCOUNT), serviceAccount);
|
|
284
|
+
});
|
|
285
|
+
it("should create the env file without values that dotenv cannot preserve", async () => {
|
|
286
|
+
const mockPayload = {
|
|
287
|
+
accountName: "test-account",
|
|
288
|
+
projectName: "test-project",
|
|
289
|
+
environmentType: "development",
|
|
290
|
+
systemConfigurations: "config-123",
|
|
291
|
+
SERIALIZABLE_VALUE: "still written",
|
|
292
|
+
UNSERIALIZABLE_VALUE: "a physical\rcarriage return, a \"double quote\", a 'single quote', and a `backtick`",
|
|
293
|
+
};
|
|
294
|
+
mockAgent
|
|
295
|
+
.get(TEST_API_ENDPOINT)
|
|
296
|
+
.intercept({
|
|
297
|
+
path: `/v1/environments/${TEST_ENVIRONMENT}/local-configurations`,
|
|
298
|
+
method: "GET",
|
|
299
|
+
headers: {
|
|
300
|
+
authorization: `Bearer ${TEST_AUTH_TOKEN}`,
|
|
301
|
+
},
|
|
302
|
+
})
|
|
303
|
+
.reply(200, mockPayload);
|
|
304
|
+
const { pullLocalConfig } = await import("../common/populate.js");
|
|
305
|
+
await nodeAssert.rejects(pullLocalConfig({
|
|
306
|
+
dir: testDir,
|
|
307
|
+
environment: TEST_ENVIRONMENT,
|
|
308
|
+
authToken: TEST_AUTH_TOKEN,
|
|
309
|
+
}), {
|
|
310
|
+
message: 'Environment variable "UNSERIALIZABLE_VALUE" was not written to .env.zuplo because its value contains a combination of single quotes, double quotes, backticks, or line breaks that dotenv cannot preserve. The file was still created without this variable.',
|
|
311
|
+
});
|
|
312
|
+
const content = await readFile(join(testDir, ".env.zuplo"), "utf-8");
|
|
313
|
+
const parsedEnv = dotenvParse(content);
|
|
314
|
+
assert.equal(parsedEnv.SERIALIZABLE_VALUE, mockPayload.SERIALIZABLE_VALUE);
|
|
315
|
+
assert.notInclude(content, "UNSERIALIZABLE_VALUE");
|
|
316
|
+
});
|
|
231
317
|
it("should only include public variables section when public variables exist", async () => {
|
|
232
318
|
const mockPayload = {
|
|
233
319
|
accountName: "test-account",
|
|
@@ -302,7 +388,7 @@ describe("pullLocalConfig", () => {
|
|
|
302
388
|
assert.include(content, 'API_KEY="secret-key-123"');
|
|
303
389
|
await rm(testDir, { recursive: true, force: true });
|
|
304
390
|
});
|
|
305
|
-
it("should
|
|
391
|
+
it("should preserve quoted and multiline environment variable values", async () => {
|
|
306
392
|
const mockPayload = {
|
|
307
393
|
accountName: "test-account",
|
|
308
394
|
projectName: "test-project",
|
|
@@ -318,6 +404,9 @@ describe("pullLocalConfig", () => {
|
|
|
318
404
|
EDGE_CASE_3: "it's a $pecial @#$%^&*() value!",
|
|
319
405
|
EDGE_CASE_4: "multi\nline\nwith'quotes",
|
|
320
406
|
EDGE_CASE_5: "tabs\tand\tspaces and 'quotes'",
|
|
407
|
+
EDGE_CASE_6: 'value with "double quotes", a `backtick`, and a literal\\nnewline',
|
|
408
|
+
EDGE_CASE_7: "value with \"double quotes\", a `backtick`, a 'single quote', and a literal\\nnewline",
|
|
409
|
+
CARRIAGE_RETURN: "before\rafter",
|
|
321
410
|
};
|
|
322
411
|
mockAgent
|
|
323
412
|
.get(TEST_API_ENDPOINT)
|
|
@@ -339,30 +428,17 @@ describe("pullLocalConfig", () => {
|
|
|
339
428
|
const content = await readFile(envFilePath, "utf-8");
|
|
340
429
|
assert.include(content, "DATABASE_URL=\"postgres://user:p'assw'ord@localhost:5432/db\"");
|
|
341
430
|
assert.include(content, "API_KEY=\"secret'with'quotes\"");
|
|
342
|
-
assert.include(content, 'JSON_CONFIG
|
|
431
|
+
assert.include(content, 'JSON_CONFIG=`{"message": "Hello \'world\'", "nested": {"value": "test\'s"}}`');
|
|
343
432
|
assert.include(content, 'ZUPLO_PUBLIC_MESSAGE="Welcome to Zuplo\'s platform!"');
|
|
344
|
-
assert.include(content,
|
|
345
|
-
assert.include(content,
|
|
346
|
-
assert.include(content, '
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
assert.equal(parsedEnv.DATABASE_URL, mockPayload.DATABASE_URL);
|
|
354
|
-
assert.equal(parsedEnv.API_KEY, mockPayload.API_KEY);
|
|
355
|
-
assert.isString(parsedEnv.JSON_CONFIG);
|
|
356
|
-
assert.include(parsedEnv.JSON_CONFIG, '\\"message\\"');
|
|
357
|
-
assert.equal(parsedEnv.ZUPLO_PUBLIC_MESSAGE, mockPayload.ZUPLO_PUBLIC_MESSAGE);
|
|
358
|
-
assert.isString(parsedEnv.COMPLEX_VALUE);
|
|
359
|
-
assert.include(parsedEnv.COMPLEX_VALUE, "special_chars");
|
|
360
|
-
assert.isString(parsedEnv.EDGE_CASE_1);
|
|
361
|
-
assert.include(parsedEnv.EDGE_CASE_1, "single");
|
|
362
|
-
assert.equal(parsedEnv.EDGE_CASE_2, mockPayload.EDGE_CASE_2);
|
|
363
|
-
assert.equal(parsedEnv.EDGE_CASE_3, mockPayload.EDGE_CASE_3);
|
|
364
|
-
assert.equal(parsedEnv.EDGE_CASE_4, mockPayload.EDGE_CASE_4);
|
|
365
|
-
assert.equal(parsedEnv.EDGE_CASE_5, mockPayload.EDGE_CASE_5);
|
|
433
|
+
assert.include(content, "EDGE_CASE_1=`value with 'single' and \"double\" quotes`");
|
|
434
|
+
assert.include(content, `EDGE_CASE_7=${mockPayload.EDGE_CASE_7}`);
|
|
435
|
+
assert.include(content, 'CARRIAGE_RETURN="before\\rafter"');
|
|
436
|
+
const parsedEnv = dotenvParse(content);
|
|
437
|
+
for (const [key, value] of Object.entries(mockPayload)) {
|
|
438
|
+
if (!SYSTEM_PAYLOAD_KEYS.includes(key)) {
|
|
439
|
+
assert.equal(parsedEnv[key], value, `${key} should round trip exactly`);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
366
442
|
await rm(testDir, { recursive: true, force: true });
|
|
367
443
|
});
|
|
368
444
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"populate.test.js","sourceRoot":"","sources":["../../src/__tests__/populate.test.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Unit tests for the pullLocalConfig and pullSystemConfig functions\n * Focuses on testing the parsing logic and environment file generation\n */\n\nimport { mkdtemp, readFile, rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\n// biome-ignore lint/correctness/noUnusedImports: Migrated from ESLint\nimport { join, parse } from \"node:path\";\nimport { afterEach, beforeEach, describe, it } from \"node:test\";\nimport { assert } from \"chai\";\nimport { parse as dotenvParse } from \"dotenv\";\nimport {\n type Dispatcher,\n getGlobalDispatcher,\n MockAgent,\n setGlobalDispatcher,\n} from \"undici\";\n\n// Test constants\nconst TEST_ENVIRONMENT = \"test-env-123\";\nconst TEST_AUTH_TOKEN = \"test-auth-token-456\";\nconst TEST_API_ENDPOINT = \"https://dev.zuplo.com\";\n\ndescribe(\"pullSystemConfig\", () => {\n let mockAgent: MockAgent;\n let previousDispatcher: Dispatcher;\n let testDir: string;\n\n beforeEach(async () => {\n // `setGlobalDispatcher` replaces process-global state, and this MockAgent\n // has net-connect disabled. This package runs `node --test`, which gives\n // each test *file* its own process, so the blast radius is the rest of\n // this file rather than the whole package — but a later suite here that\n // performed real network I/O would fail with a bare \"fetch failed\" and no\n // hint as to why. Capture what was installed and put it back, as\n // packages/runtime and packages/cloudflare-workers now do.\n previousDispatcher = getGlobalDispatcher();\n mockAgent = new MockAgent();\n mockAgent.disableNetConnect();\n setGlobalDispatcher(mockAgent);\n\n testDir = await mkdtemp(join(tmpdir(), \"zuplo-test-\"));\n });\n\n afterEach(async () => {\n await mockAgent.close();\n setGlobalDispatcher(previousDispatcher);\n await rm(testDir, { recursive: true, force: true });\n });\n\n it(\"should write account and project name to .env.zuplo\", async () => {\n const mockPayload = {\n accountName: \"test-account\",\n projectName: \"test-project\",\n environmentType: \"development\",\n systemConfigurations: \"config-123\",\n };\n\n mockAgent\n .get(TEST_API_ENDPOINT)\n .intercept({\n path: `/v1/environments/${TEST_ENVIRONMENT}/configurations`,\n method: \"GET\",\n headers: {\n authorization: `Bearer ${TEST_AUTH_TOKEN}`,\n },\n })\n .reply(200, mockPayload);\n\n const { pullSystemConfig } = await import(\"../common/populate.js\");\n\n await pullSystemConfig({\n dir: testDir,\n environment: TEST_ENVIRONMENT,\n authToken: TEST_AUTH_TOKEN,\n });\n\n const content = await readFile(join(testDir, \".env.zuplo\"), \"utf-8\");\n\n assert.include(content, \"ZUPLO_ACCOUNT_NAME=test-account\");\n assert.include(content, \"ZUPLO_PROJECT_NAME=test-project\");\n assert.include(content, \"ZUPLO_ENVIRONMENT_TYPE=development\");\n assert.include(content, \"ZUPLO_SYSTEM_CONFIGURATIONS=config-123\");\n assert.notInclude(content, \"ZUPLO_ENVIRONMENT_NAME\");\n });\n});\n\ndescribe(\"pullLocalConfig\", () => {\n let mockAgent: MockAgent;\n let previousDispatcher: Dispatcher;\n let testDir: string;\n\n beforeEach(async () => {\n // Setup HTTP mocking. See the note in `pullSystemConfig` above for why the\n // previous dispatcher is captured rather than simply overwritten.\n previousDispatcher = getGlobalDispatcher();\n mockAgent = new MockAgent();\n mockAgent.disableNetConnect();\n setGlobalDispatcher(mockAgent);\n\n // Create a temporary directory for testing\n testDir = await mkdtemp(join(tmpdir(), \"zuplo-test-\"));\n });\n\n // This suite previously had no afterEach at all: it leaked both the\n // net-connect-disabled dispatcher and (when a test failed before its inline\n // cleanup) the temp directory.\n afterEach(async () => {\n await mockAgent.close();\n setGlobalDispatcher(previousDispatcher);\n await rm(testDir, { recursive: true, force: true });\n });\n\n it(\"should generate correct .env.zuplo file with system variables\", async () => {\n const mockPayload = {\n accountName: \"test-account\",\n projectName: \"test-project\",\n environmentType: \"development\",\n systemConfigurations: \"config-123\",\n };\n\n // Mock successful API response\n mockAgent\n .get(TEST_API_ENDPOINT)\n .intercept({\n path: `/v1/environments/${TEST_ENVIRONMENT}/local-configurations`,\n method: \"GET\",\n headers: {\n authorization: `Bearer ${TEST_AUTH_TOKEN}`,\n },\n })\n .reply(200, mockPayload);\n\n const { pullLocalConfig } = await import(\"../common/populate.js\");\n\n await pullLocalConfig({\n dir: testDir,\n environment: TEST_ENVIRONMENT,\n authToken: TEST_AUTH_TOKEN,\n });\n\n // Verify the .env.zuplo file was created\n const envFilePath = join(testDir, \".env.zuplo\");\n const content = await readFile(envFilePath, \"utf-8\");\n\n // Verify file header\n assert.include(\n content,\n \"# This file is auto-generated from zuplo link. Please do not edit it manually.\"\n );\n assert.include(\n content,\n \"# It will be auto-generated afresh the next time you run zuplo link.\"\n );\n assert.include(\n content,\n \"# If you wish to add your own environment variables, create a separate .env file.\"\n );\n\n // Verify system variables are present\n assert.include(content, \"ZUPLO_ACCOUNT_NAME=test-account\");\n assert.include(content, \"ZUPLO_PROJECT_NAME=test-project\");\n assert.include(content, \"ZUPLO_ENVIRONMENT_TYPE=development\");\n assert.include(content, \"ZUPLO_SYSTEM_CONFIGURATIONS=config-123\");\n assert.notInclude(content, \"ZUPLO_ENVIRONMENT_NAME\");\n\n // Verify sections are NOT present when there are no variables for them\n assert.notInclude(content, \"# Public Zuplo environment variables\");\n assert.notInclude(\n content,\n \"# Environment variables defined in the Zuplo UI for the environment\"\n );\n\n // Clean up\n await rm(testDir, { recursive: true, force: true });\n });\n\n it(\"should handle payload with public and user environment variables\", async () => {\n const mockPayload = {\n accountName: \"my-account\",\n projectName: \"my-project\",\n environmentType: \"production\",\n systemConfigurations: \"prod-config-456\",\n // Public variables (should be in public section)\n ZUPLO_PUBLIC_API_URL: \"https://api.example.com\",\n ZUPLO_PUBLIC_DOCS_URL: \"https://docs.example.com\",\n // User variables (should be in user section)\n DATABASE_URL: \"postgres://localhost:5432/db\",\n API_KEY: \"secret-key-123\",\n REDIS_URL: \"redis://localhost:6379\",\n };\n\n // Mock successful API response\n mockAgent\n .get(TEST_API_ENDPOINT)\n .intercept({\n path: `/v1/environments/${TEST_ENVIRONMENT}/local-configurations`,\n method: \"GET\",\n headers: {\n authorization: `Bearer ${TEST_AUTH_TOKEN}`,\n },\n })\n .reply(200, mockPayload);\n\n const { pullLocalConfig } = await import(\"../common/populate.js\");\n\n await pullLocalConfig({\n dir: testDir,\n environment: TEST_ENVIRONMENT,\n authToken: TEST_AUTH_TOKEN,\n });\n\n // Read the generated file\n const envFilePath = join(testDir, \".env.zuplo\");\n const content = await readFile(envFilePath, \"utf-8\");\n\n // Verify system variables\n assert.include(content, \"ZUPLO_ACCOUNT_NAME=my-account\");\n assert.include(content, \"ZUPLO_PROJECT_NAME=my-project\");\n assert.include(content, \"ZUPLO_ENVIRONMENT_TYPE=production\");\n assert.include(content, \"ZUPLO_SYSTEM_CONFIGURATIONS=prod-config-456\");\n\n // Verify public variables are in the public section\n const publicSectionRegex =\n /# Public Zuplo environment variables[\\s\\S]*?(?=# Environment variables defined in the Zuplo UI|$)/;\n const publicSection = content.match(publicSectionRegex)?.[0] || \"\";\n assert.include(\n publicSection,\n 'ZUPLO_PUBLIC_API_URL=\"https://api.example.com\"'\n );\n assert.include(\n publicSection,\n 'ZUPLO_PUBLIC_DOCS_URL=\"https://docs.example.com\"'\n );\n\n // Verify user variables are in the user section\n const userSectionRegex =\n /# Environment variables defined in the Zuplo UI[\\s\\S]*$/;\n const userSection = content.match(userSectionRegex)?.[0] || \"\";\n assert.include(userSection, 'DATABASE_URL=\"postgres://localhost:5432/db\"');\n assert.include(userSection, 'API_KEY=\"secret-key-123\"');\n assert.include(userSection, 'REDIS_URL=\"redis://localhost:6379\"');\n\n // Verify system variables are NOT in user section\n assert.notInclude(userSection, \"accountName=\");\n assert.notInclude(userSection, \"projectName=\");\n assert.notInclude(userSection, \"environmentType=\");\n assert.notInclude(userSection, \"systemConfigurations=\");\n\n // Clean up\n await rm(testDir, { recursive: true, force: true });\n });\n\n it(\"should handle empty environment variables gracefully\", async () => {\n const mockPayload = {\n accountName: \"test-account\",\n projectName: \"test-project\",\n environmentType: \"development\",\n systemConfigurations: \"config-789\",\n // No additional environment variables\n };\n\n // Mock successful API response\n mockAgent\n .get(TEST_API_ENDPOINT)\n .intercept({\n path: `/v1/environments/${TEST_ENVIRONMENT}/local-configurations`,\n method: \"GET\",\n headers: {\n authorization: `Bearer ${TEST_AUTH_TOKEN}`,\n },\n })\n .reply(200, mockPayload);\n\n const { pullLocalConfig } = await import(\"../common/populate.js\");\n\n await pullLocalConfig({\n dir: testDir,\n environment: TEST_ENVIRONMENT,\n authToken: TEST_AUTH_TOKEN,\n });\n\n // Read the generated file\n const envFilePath = join(testDir, \".env.zuplo\");\n const content = await readFile(envFilePath, \"utf-8\");\n\n // Verify system variables are still present\n assert.include(content, \"ZUPLO_ACCOUNT_NAME=test-account\");\n assert.include(content, \"ZUPLO_PROJECT_NAME=test-project\");\n assert.include(content, \"ZUPLO_ENVIRONMENT_TYPE=development\");\n assert.include(content, \"ZUPLO_SYSTEM_CONFIGURATIONS=config-789\");\n\n // Verify sections are NOT present when there are no variables for them\n assert.notInclude(content, \"# Public Zuplo environment variables\");\n assert.notInclude(\n content,\n \"# Environment variables defined in the Zuplo UI for the environment\"\n );\n\n // Clean up\n await rm(testDir, { recursive: true, force: true });\n });\n\n it(\"should handle special characters in environment variable values\", async () => {\n const mockPayload = {\n accountName: \"test-account\",\n projectName: \"test-project\",\n environmentType: \"development\",\n systemConfigurations: \"config-123\",\n DATABASE_URL: \"postgres://user:p@ssw0rd!@localhost:5432/db?ssl=true\",\n API_SECRET: \"secret-with-special-chars!@#$%^&*()\",\n JSON_CONFIG: '{\"key\": \"value\", \"nested\": {\"array\": [1, 2, 3]}}',\n };\n\n // Mock successful API response\n mockAgent\n .get(TEST_API_ENDPOINT)\n .intercept({\n path: `/v1/environments/${TEST_ENVIRONMENT}/local-configurations`,\n method: \"GET\",\n headers: {\n authorization: `Bearer ${TEST_AUTH_TOKEN}`,\n },\n })\n .reply(200, mockPayload);\n\n const { pullLocalConfig } = await import(\"../common/populate.js\");\n\n await pullLocalConfig({\n dir: testDir,\n environment: TEST_ENVIRONMENT,\n authToken: TEST_AUTH_TOKEN,\n });\n\n // Read the generated file\n const envFilePath = join(testDir, \".env.zuplo\");\n const content = await readFile(envFilePath, \"utf-8\");\n\n // Verify special characters are preserved in environment variable values\n assert.include(\n content,\n 'DATABASE_URL=\"postgres://user:p@ssw0rd!@localhost:5432/db?ssl=true\"'\n );\n assert.include(content, 'API_SECRET=\"secret-with-special-chars!@#$%^&*()\"');\n assert.include(\n content,\n 'JSON_CONFIG=\"{\\\\\"key\\\\\": \\\\\"value\\\\\", \\\\\"nested\\\\\": {\\\\\"array\\\\\": [1, 2, 3]}}\"'\n );\n\n // Verify these are in the user section (not public section)\n const userSectionRegex =\n /# Environment variables defined in the Zuplo UI[\\s\\S]*$/;\n const userSection = content.match(userSectionRegex)?.[0] || \"\";\n assert.include(\n userSection,\n 'DATABASE_URL=\"postgres://user:p@ssw0rd!@localhost:5432/db?ssl=true\"'\n );\n assert.include(\n userSection,\n 'API_SECRET=\"secret-with-special-chars!@#$%^&*()\"'\n );\n assert.include(\n userSection,\n 'JSON_CONFIG=\"{\\\\\"key\\\\\": \\\\\"value\\\\\", \\\\\"nested\\\\\": {\\\\\"array\\\\\": [1, 2, 3]}}\"'\n );\n\n // Clean up\n await rm(testDir, { recursive: true, force: true });\n });\n\n it(\"should only include public variables section when public variables exist\", async () => {\n const mockPayload = {\n accountName: \"test-account\",\n projectName: \"test-project\",\n environmentType: \"development\",\n systemConfigurations: \"config-123\",\n // Only public variables, no user variables\n ZUPLO_PUBLIC_API_URL: \"https://api.example.com\",\n ZUPLO_PUBLIC_DOCS_URL: \"https://docs.example.com\",\n };\n\n // Mock successful API response\n mockAgent\n .get(TEST_API_ENDPOINT)\n .intercept({\n path: `/v1/environments/${TEST_ENVIRONMENT}/local-configurations`,\n method: \"GET\",\n headers: {\n authorization: `Bearer ${TEST_AUTH_TOKEN}`,\n },\n })\n .reply(200, mockPayload);\n\n const { pullLocalConfig } = await import(\"../common/populate.js\");\n\n await pullLocalConfig({\n dir: testDir,\n environment: TEST_ENVIRONMENT,\n authToken: TEST_AUTH_TOKEN,\n });\n\n // Read the generated file\n const envFilePath = join(testDir, \".env.zuplo\");\n const content = await readFile(envFilePath, \"utf-8\");\n\n // Verify system variables are present\n assert.include(content, \"ZUPLO_ACCOUNT_NAME=test-account\");\n assert.include(content, \"ZUPLO_PROJECT_NAME=test-project\");\n assert.include(content, \"ZUPLO_ENVIRONMENT_TYPE=development\");\n assert.include(content, \"ZUPLO_SYSTEM_CONFIGURATIONS=config-123\");\n\n // Verify public section is present with variables\n assert.include(content, \"# Public Zuplo environment variables\");\n assert.include(content, 'ZUPLO_PUBLIC_API_URL=\"https://api.example.com\"');\n assert.include(content, 'ZUPLO_PUBLIC_DOCS_URL=\"https://docs.example.com\"');\n\n // Verify user section is NOT present since there are no user variables\n assert.notInclude(\n content,\n \"# Environment variables defined in the Zuplo UI for the environment\"\n );\n\n // Clean up\n await rm(testDir, { recursive: true, force: true });\n });\n\n it(\"should only include user variables section when user variables exist\", async () => {\n const mockPayload = {\n accountName: \"test-account\",\n projectName: \"test-project\",\n environmentType: \"development\",\n systemConfigurations: \"config-123\",\n // Only user variables, no public variables\n DATABASE_URL: \"postgres://localhost:5432/db\",\n API_KEY: \"secret-key-123\",\n };\n\n // Mock successful API response\n mockAgent\n .get(TEST_API_ENDPOINT)\n .intercept({\n path: `/v1/environments/${TEST_ENVIRONMENT}/local-configurations`,\n method: \"GET\",\n headers: {\n authorization: `Bearer ${TEST_AUTH_TOKEN}`,\n },\n })\n .reply(200, mockPayload);\n\n const { pullLocalConfig } = await import(\"../common/populate.js\");\n\n await pullLocalConfig({\n dir: testDir,\n environment: TEST_ENVIRONMENT,\n authToken: TEST_AUTH_TOKEN,\n });\n\n // Read the generated file\n const envFilePath = join(testDir, \".env.zuplo\");\n const content = await readFile(envFilePath, \"utf-8\");\n\n // Verify system variables are present\n assert.include(content, \"ZUPLO_ACCOUNT_NAME=test-account\");\n assert.include(content, \"ZUPLO_PROJECT_NAME=test-project\");\n assert.include(content, \"ZUPLO_ENVIRONMENT_TYPE=development\");\n assert.include(content, \"ZUPLO_SYSTEM_CONFIGURATIONS=config-123\");\n\n // Verify public section is NOT present since there are no public variables\n assert.notInclude(content, \"# Public Zuplo environment variables\");\n\n // Verify user section is present with variables\n assert.include(\n content,\n \"# Environment variables defined in the Zuplo UI for the environment\"\n );\n assert.include(content, 'DATABASE_URL=\"postgres://localhost:5432/db\"');\n assert.include(content, 'API_KEY=\"secret-key-123\"');\n\n // Clean up\n await rm(testDir, { recursive: true, force: true });\n });\n\n it(\"should properly escape double quotes in environment variable values for dotenv parsing\", async () => {\n const mockPayload = {\n accountName: \"test-account\",\n projectName: \"test-project\",\n environmentType: \"development\",\n systemConfigurations: \"config-123\",\n // Environment variables with double quotes that need escaping\n DATABASE_URL: \"postgres://user:p'assw'ord@localhost:5432/db\",\n API_KEY: \"secret'with'quotes\",\n JSON_CONFIG:\n '{\"message\": \"Hello \\'world\\'\", \"nested\": {\"value\": \"test\\'s\"}}',\n ZUPLO_PUBLIC_MESSAGE: \"Welcome to Zuplo's platform!\",\n COMPLEX_VALUE: \"?\\\\\\\"!##==A_special_chars'''\",\n // Additional special character test cases\n EDGE_CASE_1: \"value with 'single' and \\\"double\\\" quotes\",\n EDGE_CASE_2: \"path\\\\to\\\\file's location\",\n EDGE_CASE_3: \"it's a $pecial @#$%^&*() value!\",\n EDGE_CASE_4: \"multi\\nline\\nwith'quotes\",\n EDGE_CASE_5: \"tabs\\tand\\tspaces and 'quotes'\",\n };\n\n // Mock successful API response\n mockAgent\n .get(TEST_API_ENDPOINT)\n .intercept({\n path: `/v1/environments/${TEST_ENVIRONMENT}/local-configurations`,\n method: \"GET\",\n headers: {\n authorization: `Bearer ${TEST_AUTH_TOKEN}`,\n },\n })\n .reply(200, mockPayload);\n\n const { pullLocalConfig } = await import(\"../common/populate.js\");\n\n await pullLocalConfig({\n dir: testDir,\n environment: TEST_ENVIRONMENT,\n authToken: TEST_AUTH_TOKEN,\n });\n\n // Read the generated file\n const envFilePath = join(testDir, \".env.zuplo\");\n const content = await readFile(envFilePath, \"utf-8\");\n\n // Verify that all values use double quotes with escaped double quotes\n assert.include(\n content,\n \"DATABASE_URL=\\\"postgres://user:p'assw'ord@localhost:5432/db\\\"\"\n );\n assert.include(content, \"API_KEY=\\\"secret'with'quotes\\\"\");\n assert.include(\n content,\n 'JSON_CONFIG=\"{\\\\\"message\\\\\": \\\\\"Hello \\'world\\'\\\\\", \\\\\"nested\\\\\": {\\\\\"value\\\\\": \\\\\"test\\'s\\\\\"}}\"'\n );\n assert.include(\n content,\n 'ZUPLO_PUBLIC_MESSAGE=\"Welcome to Zuplo\\'s platform!\"'\n );\n assert.include(content, `COMPLEX_VALUE=\"?\\\\\\\\\"!##==A_special_chars'''\"`);\n\n // Verify additional edge cases use double quotes with escaped double quotes\n assert.include(\n content,\n 'EDGE_CASE_1=\"value with \\'single\\' and \\\\\"double\\\\\" quotes\"'\n );\n assert.include(content, 'EDGE_CASE_2=\"path\\\\to\\\\file\\'s location\"');\n assert.include(content, 'EDGE_CASE_3=\"it\\'s a $pecial @#$%^&*() value!\"');\n assert.include(content, 'EDGE_CASE_4=\"multi\\nline\\nwith\\'quotes\"');\n assert.include(content, \"EDGE_CASE_5=\\\"tabs\\tand\\tspaces and 'quotes'\\\"\");\n\n // Test that dotenv can properly parse the generated file\n const fileContent = await readFile(envFilePath, \"utf-8\");\n const parsedEnv = dotenvParse(fileContent);\n\n // Verify that dotenv successfully parsed the file without errors\n assert.isUndefined(\n parsedEnv.error,\n \"dotenv should parse the file without errors\"\n );\n\n // Verify that the parsed values match the original values from the mock payload\n // Note: dotenv may not perfectly unescape all values, but should parse without errors\n assert.equal(parsedEnv.DATABASE_URL, mockPayload.DATABASE_URL);\n assert.equal(parsedEnv.API_KEY, mockPayload.API_KEY);\n // For JSON_CONFIG, dotenv doesn't unescape the quotes, so we check that it contains the escaped version\n assert.isString(parsedEnv.JSON_CONFIG);\n assert.include(parsedEnv.JSON_CONFIG, '\\\\\"message\\\\\"');\n assert.equal(\n parsedEnv.ZUPLO_PUBLIC_MESSAGE,\n mockPayload.ZUPLO_PUBLIC_MESSAGE\n );\n // For COMPLEX_VALUE, dotenv doesn't unescape the backslash-escaped quotes properly\n assert.isString(parsedEnv.COMPLEX_VALUE);\n assert.include(parsedEnv.COMPLEX_VALUE, \"special_chars\");\n\n // Verify additional edge cases are parsed correctly\n // For values with double quotes, dotenv may not unescape them perfectly\n assert.isString(parsedEnv.EDGE_CASE_1);\n assert.include(parsedEnv.EDGE_CASE_1, \"single\");\n assert.equal(parsedEnv.EDGE_CASE_2, mockPayload.EDGE_CASE_2);\n assert.equal(parsedEnv.EDGE_CASE_3, mockPayload.EDGE_CASE_3);\n assert.equal(parsedEnv.EDGE_CASE_4, mockPayload.EDGE_CASE_4);\n assert.equal(parsedEnv.EDGE_CASE_5, mockPayload.EDGE_CASE_5);\n\n // Clean up\n await rm(testDir, { recursive: true, force: true });\n });\n});\n"]}
|
|
1
|
+
{"version":3,"file":"populate.test.js","sourceRoot":"","sources":["../../src/__tests__/populate.test.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Unit tests for the pullLocalConfig and pullSystemConfig functions\n * Focuses on testing the parsing logic and environment file generation\n */\n\nimport { strict as nodeAssert } from \"node:assert\";\nimport { mkdtemp, readFile, rm } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\n// biome-ignore lint/correctness/noUnusedImports: Migrated from ESLint\nimport { join, parse } from \"node:path\";\nimport { afterEach, beforeEach, describe, it } from \"node:test\";\nimport { assert } from \"chai\";\nimport { parse as dotenvParse } from \"dotenv\";\nimport {\n type Dispatcher,\n getGlobalDispatcher,\n MockAgent,\n setGlobalDispatcher,\n} from \"undici\";\n\n// Test constants\nconst TEST_ENVIRONMENT = \"test-env-123\";\nconst TEST_AUTH_TOKEN = \"test-auth-token-456\";\nconst TEST_API_ENDPOINT = \"https://dev.zuplo.com\";\nconst SYSTEM_PAYLOAD_KEYS = [\n \"accountName\",\n \"projectName\",\n \"environmentType\",\n \"systemConfigurations\",\n];\n\ndescribe(\"pullSystemConfig\", () => {\n let mockAgent: MockAgent;\n let previousDispatcher: Dispatcher;\n let testDir: string;\n\n beforeEach(async () => {\n // `setGlobalDispatcher` replaces process-global state, and this MockAgent\n // has net-connect disabled. This package runs `node --test`, which gives\n // each test *file* its own process, so the blast radius is the rest of\n // this file rather than the whole package — but a later suite here that\n // performed real network I/O would fail with a bare \"fetch failed\" and no\n // hint as to why. Capture what was installed and put it back, as\n // packages/runtime and packages/cloudflare-workers now do.\n previousDispatcher = getGlobalDispatcher();\n mockAgent = new MockAgent();\n mockAgent.disableNetConnect();\n setGlobalDispatcher(mockAgent);\n\n testDir = await mkdtemp(join(tmpdir(), \"zuplo-test-\"));\n });\n\n afterEach(async () => {\n await mockAgent.close();\n setGlobalDispatcher(previousDispatcher);\n await rm(testDir, { recursive: true, force: true });\n });\n\n it(\"should write account and project name to .env.zuplo\", async () => {\n const mockPayload = {\n accountName: \"test-account\",\n projectName: \"test-project\",\n environmentType: \"development\",\n systemConfigurations: \"config-123\",\n };\n\n mockAgent\n .get(TEST_API_ENDPOINT)\n .intercept({\n path: `/v1/environments/${TEST_ENVIRONMENT}/configurations`,\n method: \"GET\",\n headers: {\n authorization: `Bearer ${TEST_AUTH_TOKEN}`,\n },\n })\n .reply(200, mockPayload);\n\n const { pullSystemConfig } = await import(\"../common/populate.js\");\n\n await pullSystemConfig({\n dir: testDir,\n environment: TEST_ENVIRONMENT,\n authToken: TEST_AUTH_TOKEN,\n });\n\n const content = await readFile(join(testDir, \".env.zuplo\"), \"utf-8\");\n\n assert.include(content, \"ZUPLO_ACCOUNT_NAME=test-account\");\n assert.include(content, \"ZUPLO_PROJECT_NAME=test-project\");\n assert.include(content, \"ZUPLO_ENVIRONMENT_TYPE=development\");\n assert.include(content, \"ZUPLO_SYSTEM_CONFIGURATIONS=config-123\");\n assert.notInclude(content, \"ZUPLO_ENVIRONMENT_NAME\");\n });\n});\n\ndescribe(\"pullLocalConfig\", () => {\n let mockAgent: MockAgent;\n let previousDispatcher: Dispatcher;\n let testDir: string;\n\n beforeEach(async () => {\n // Setup HTTP mocking. See the note in `pullSystemConfig` above for why the\n // previous dispatcher is captured rather than simply overwritten.\n previousDispatcher = getGlobalDispatcher();\n mockAgent = new MockAgent();\n mockAgent.disableNetConnect();\n setGlobalDispatcher(mockAgent);\n\n // Create a temporary directory for testing\n testDir = await mkdtemp(join(tmpdir(), \"zuplo-test-\"));\n });\n\n // This suite previously had no afterEach at all: it leaked both the\n // net-connect-disabled dispatcher and (when a test failed before its inline\n // cleanup) the temp directory.\n afterEach(async () => {\n await mockAgent.close();\n setGlobalDispatcher(previousDispatcher);\n await rm(testDir, { recursive: true, force: true });\n });\n\n it(\"should generate correct .env.zuplo file with system variables\", async () => {\n const mockPayload = {\n accountName: \"test-account\",\n projectName: \"test-project\",\n environmentType: \"development\",\n systemConfigurations: \"config-123\",\n };\n\n // Mock successful API response\n mockAgent\n .get(TEST_API_ENDPOINT)\n .intercept({\n path: `/v1/environments/${TEST_ENVIRONMENT}/local-configurations`,\n method: \"GET\",\n headers: {\n authorization: `Bearer ${TEST_AUTH_TOKEN}`,\n },\n })\n .reply(200, mockPayload);\n\n const { pullLocalConfig } = await import(\"../common/populate.js\");\n\n await pullLocalConfig({\n dir: testDir,\n environment: TEST_ENVIRONMENT,\n authToken: TEST_AUTH_TOKEN,\n });\n\n // Verify the .env.zuplo file was created\n const envFilePath = join(testDir, \".env.zuplo\");\n const content = await readFile(envFilePath, \"utf-8\");\n\n // Verify file header\n assert.include(\n content,\n \"# This file is auto-generated from zuplo link. Please do not edit it manually.\"\n );\n assert.include(\n content,\n \"# It will be auto-generated afresh the next time you run zuplo link.\"\n );\n assert.include(\n content,\n \"# If you wish to add your own environment variables, create a separate .env file.\"\n );\n\n // Verify system variables are present\n assert.include(content, \"ZUPLO_ACCOUNT_NAME=test-account\");\n assert.include(content, \"ZUPLO_PROJECT_NAME=test-project\");\n assert.include(content, \"ZUPLO_ENVIRONMENT_TYPE=development\");\n assert.include(content, \"ZUPLO_SYSTEM_CONFIGURATIONS=config-123\");\n assert.notInclude(content, \"ZUPLO_ENVIRONMENT_NAME\");\n\n // Verify sections are NOT present when there are no variables for them\n assert.notInclude(content, \"# Public Zuplo environment variables\");\n assert.notInclude(\n content,\n \"# Environment variables defined in the Zuplo UI for the environment\"\n );\n\n // Clean up\n await rm(testDir, { recursive: true, force: true });\n });\n\n it(\"should handle payload with public and user environment variables\", async () => {\n const mockPayload = {\n accountName: \"my-account\",\n projectName: \"my-project\",\n environmentType: \"production\",\n systemConfigurations: \"prod-config-456\",\n // Public variables (should be in public section)\n ZUPLO_PUBLIC_API_URL: \"https://api.example.com\",\n ZUPLO_PUBLIC_DOCS_URL: \"https://docs.example.com\",\n // User variables (should be in user section)\n DATABASE_URL: \"postgres://localhost:5432/db\",\n API_KEY: \"secret-key-123\",\n REDIS_URL: \"redis://localhost:6379\",\n };\n\n // Mock successful API response\n mockAgent\n .get(TEST_API_ENDPOINT)\n .intercept({\n path: `/v1/environments/${TEST_ENVIRONMENT}/local-configurations`,\n method: \"GET\",\n headers: {\n authorization: `Bearer ${TEST_AUTH_TOKEN}`,\n },\n })\n .reply(200, mockPayload);\n\n const { pullLocalConfig } = await import(\"../common/populate.js\");\n\n await pullLocalConfig({\n dir: testDir,\n environment: TEST_ENVIRONMENT,\n authToken: TEST_AUTH_TOKEN,\n });\n\n // Read the generated file\n const envFilePath = join(testDir, \".env.zuplo\");\n const content = await readFile(envFilePath, \"utf-8\");\n\n // Verify system variables\n assert.include(content, \"ZUPLO_ACCOUNT_NAME=my-account\");\n assert.include(content, \"ZUPLO_PROJECT_NAME=my-project\");\n assert.include(content, \"ZUPLO_ENVIRONMENT_TYPE=production\");\n assert.include(content, \"ZUPLO_SYSTEM_CONFIGURATIONS=prod-config-456\");\n\n // Verify public variables are in the public section\n const publicSectionRegex =\n /# Public Zuplo environment variables[\\s\\S]*?(?=# Environment variables defined in the Zuplo UI|$)/;\n const publicSection = content.match(publicSectionRegex)?.[0] || \"\";\n assert.include(\n publicSection,\n 'ZUPLO_PUBLIC_API_URL=\"https://api.example.com\"'\n );\n assert.include(\n publicSection,\n 'ZUPLO_PUBLIC_DOCS_URL=\"https://docs.example.com\"'\n );\n\n // Verify user variables are in the user section\n const userSectionRegex =\n /# Environment variables defined in the Zuplo UI[\\s\\S]*$/;\n const userSection = content.match(userSectionRegex)?.[0] || \"\";\n assert.include(userSection, 'DATABASE_URL=\"postgres://localhost:5432/db\"');\n assert.include(userSection, 'API_KEY=\"secret-key-123\"');\n assert.include(userSection, 'REDIS_URL=\"redis://localhost:6379\"');\n\n // Verify system variables are NOT in user section\n assert.notInclude(userSection, \"accountName=\");\n assert.notInclude(userSection, \"projectName=\");\n assert.notInclude(userSection, \"environmentType=\");\n assert.notInclude(userSection, \"systemConfigurations=\");\n\n // Clean up\n await rm(testDir, { recursive: true, force: true });\n });\n\n it(\"should handle empty environment variables gracefully\", async () => {\n const mockPayload = {\n accountName: \"test-account\",\n projectName: \"test-project\",\n environmentType: \"development\",\n systemConfigurations: \"config-789\",\n // No additional environment variables\n };\n\n // Mock successful API response\n mockAgent\n .get(TEST_API_ENDPOINT)\n .intercept({\n path: `/v1/environments/${TEST_ENVIRONMENT}/local-configurations`,\n method: \"GET\",\n headers: {\n authorization: `Bearer ${TEST_AUTH_TOKEN}`,\n },\n })\n .reply(200, mockPayload);\n\n const { pullLocalConfig } = await import(\"../common/populate.js\");\n\n await pullLocalConfig({\n dir: testDir,\n environment: TEST_ENVIRONMENT,\n authToken: TEST_AUTH_TOKEN,\n });\n\n // Read the generated file\n const envFilePath = join(testDir, \".env.zuplo\");\n const content = await readFile(envFilePath, \"utf-8\");\n\n // Verify system variables are still present\n assert.include(content, \"ZUPLO_ACCOUNT_NAME=test-account\");\n assert.include(content, \"ZUPLO_PROJECT_NAME=test-project\");\n assert.include(content, \"ZUPLO_ENVIRONMENT_TYPE=development\");\n assert.include(content, \"ZUPLO_SYSTEM_CONFIGURATIONS=config-789\");\n\n // Verify sections are NOT present when there are no variables for them\n assert.notInclude(content, \"# Public Zuplo environment variables\");\n assert.notInclude(\n content,\n \"# Environment variables defined in the Zuplo UI for the environment\"\n );\n\n // Clean up\n await rm(testDir, { recursive: true, force: true });\n });\n\n it(\"should handle special characters in environment variable values\", async () => {\n const mockPayload = {\n accountName: \"test-account\",\n projectName: \"test-project\",\n environmentType: \"development\",\n systemConfigurations: \"config-123\",\n DATABASE_URL: \"postgres://user:p@ssw0rd!@localhost:5432/db?ssl=true\",\n API_SECRET: \"secret-with-special-chars!@#$%^&*()\",\n JSON_CONFIG: '{\"key\": \"value\", \"nested\": {\"array\": [1, 2, 3]}}',\n };\n\n // Mock successful API response\n mockAgent\n .get(TEST_API_ENDPOINT)\n .intercept({\n path: `/v1/environments/${TEST_ENVIRONMENT}/local-configurations`,\n method: \"GET\",\n headers: {\n authorization: `Bearer ${TEST_AUTH_TOKEN}`,\n },\n })\n .reply(200, mockPayload);\n\n const { pullLocalConfig } = await import(\"../common/populate.js\");\n\n await pullLocalConfig({\n dir: testDir,\n environment: TEST_ENVIRONMENT,\n authToken: TEST_AUTH_TOKEN,\n });\n\n // Read the generated file\n const envFilePath = join(testDir, \".env.zuplo\");\n const content = await readFile(envFilePath, \"utf-8\");\n\n // Simple values remain double quoted, while JSON uses backticks so its\n // double quotes are preserved without escaping.\n assert.include(\n content,\n 'DATABASE_URL=\"postgres://user:p@ssw0rd!@localhost:5432/db?ssl=true\"'\n );\n assert.include(content, 'API_SECRET=\"secret-with-special-chars!@#$%^&*()\"');\n assert.include(\n content,\n 'JSON_CONFIG=`{\"key\": \"value\", \"nested\": {\"array\": [1, 2, 3]}}`'\n );\n\n // Verify these are in the user section (not public section)\n const userSectionRegex =\n /# Environment variables defined in the Zuplo UI[\\s\\S]*$/;\n const userSection = content.match(userSectionRegex)?.[0] || \"\";\n assert.include(userSection, \"DATABASE_URL=\");\n assert.include(userSection, \"API_SECRET=\");\n assert.include(userSection, \"JSON_CONFIG=\");\n\n const parsedEnv = dotenvParse(content);\n assert.equal(parsedEnv.DATABASE_URL, mockPayload.DATABASE_URL);\n assert.equal(parsedEnv.API_SECRET, mockPayload.API_SECRET);\n assert.equal(parsedEnv.JSON_CONFIG, mockPayload.JSON_CONFIG);\n\n // Clean up\n await rm(testDir, { recursive: true, force: true });\n });\n\n it(\"should preserve a Google service account JSON value\", async () => {\n const serviceAccount = {\n type: \"service_account\",\n project_id: \"test-project\",\n private_key_id: \"test-key-id\",\n private_key:\n \"-----BEGIN PRIVATE KEY-----\\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASC\\n-----END PRIVATE KEY-----\\n\",\n client_email: \"test-service-account@test-project.iam.gserviceaccount.com\",\n client_id: \"1234567890\",\n auth_uri: \"https://accounts.google.com/o/oauth2/auth\",\n token_uri: \"https://oauth2.googleapis.com/token\",\n auth_provider_x509_cert_url: \"https://www.googleapis.com/oauth2/v1/certs\",\n client_x509_cert_url:\n \"https://www.googleapis.com/robot/v1/metadata/x509/test-service-account%40test-project.iam.gserviceaccount.com\",\n universe_domain: \"googleapis.com\",\n };\n const mockPayload = {\n accountName: \"test-account\",\n projectName: \"test-project\",\n environmentType: \"development\",\n systemConfigurations: \"config-123\",\n GOOGLE_SERVICE_ACCOUNT: JSON.stringify(serviceAccount, null, 2),\n };\n\n mockAgent\n .get(TEST_API_ENDPOINT)\n .intercept({\n path: `/v1/environments/${TEST_ENVIRONMENT}/local-configurations`,\n method: \"GET\",\n headers: {\n authorization: `Bearer ${TEST_AUTH_TOKEN}`,\n },\n })\n .reply(200, mockPayload);\n\n const { pullLocalConfig } = await import(\"../common/populate.js\");\n\n await pullLocalConfig({\n dir: testDir,\n environment: TEST_ENVIRONMENT,\n authToken: TEST_AUTH_TOKEN,\n });\n\n const content = await readFile(join(testDir, \".env.zuplo\"), \"utf-8\");\n assert.include(\n content,\n 'GOOGLE_SERVICE_ACCOUNT=`{\\n \"type\": \"service_account\"'\n );\n\n const parsedEnv = dotenvParse(content);\n assert.equal(\n parsedEnv.GOOGLE_SERVICE_ACCOUNT,\n mockPayload.GOOGLE_SERVICE_ACCOUNT\n );\n assert.deepEqual(\n JSON.parse(parsedEnv.GOOGLE_SERVICE_ACCOUNT),\n serviceAccount\n );\n });\n\n it(\"should create the env file without values that dotenv cannot preserve\", async () => {\n const mockPayload = {\n accountName: \"test-account\",\n projectName: \"test-project\",\n environmentType: \"development\",\n systemConfigurations: \"config-123\",\n SERIALIZABLE_VALUE: \"still written\",\n UNSERIALIZABLE_VALUE:\n \"a physical\\rcarriage return, a \\\"double quote\\\", a 'single quote', and a `backtick`\",\n };\n\n mockAgent\n .get(TEST_API_ENDPOINT)\n .intercept({\n path: `/v1/environments/${TEST_ENVIRONMENT}/local-configurations`,\n method: \"GET\",\n headers: {\n authorization: `Bearer ${TEST_AUTH_TOKEN}`,\n },\n })\n .reply(200, mockPayload);\n\n const { pullLocalConfig } = await import(\"../common/populate.js\");\n\n await nodeAssert.rejects(\n pullLocalConfig({\n dir: testDir,\n environment: TEST_ENVIRONMENT,\n authToken: TEST_AUTH_TOKEN,\n }),\n {\n message:\n 'Environment variable \"UNSERIALIZABLE_VALUE\" was not written to .env.zuplo because its value contains a combination of single quotes, double quotes, backticks, or line breaks that dotenv cannot preserve. The file was still created without this variable.',\n }\n );\n\n const content = await readFile(join(testDir, \".env.zuplo\"), \"utf-8\");\n const parsedEnv = dotenvParse(content);\n\n assert.equal(parsedEnv.SERIALIZABLE_VALUE, mockPayload.SERIALIZABLE_VALUE);\n assert.notInclude(content, \"UNSERIALIZABLE_VALUE\");\n });\n\n it(\"should only include public variables section when public variables exist\", async () => {\n const mockPayload = {\n accountName: \"test-account\",\n projectName: \"test-project\",\n environmentType: \"development\",\n systemConfigurations: \"config-123\",\n // Only public variables, no user variables\n ZUPLO_PUBLIC_API_URL: \"https://api.example.com\",\n ZUPLO_PUBLIC_DOCS_URL: \"https://docs.example.com\",\n };\n\n // Mock successful API response\n mockAgent\n .get(TEST_API_ENDPOINT)\n .intercept({\n path: `/v1/environments/${TEST_ENVIRONMENT}/local-configurations`,\n method: \"GET\",\n headers: {\n authorization: `Bearer ${TEST_AUTH_TOKEN}`,\n },\n })\n .reply(200, mockPayload);\n\n const { pullLocalConfig } = await import(\"../common/populate.js\");\n\n await pullLocalConfig({\n dir: testDir,\n environment: TEST_ENVIRONMENT,\n authToken: TEST_AUTH_TOKEN,\n });\n\n // Read the generated file\n const envFilePath = join(testDir, \".env.zuplo\");\n const content = await readFile(envFilePath, \"utf-8\");\n\n // Verify system variables are present\n assert.include(content, \"ZUPLO_ACCOUNT_NAME=test-account\");\n assert.include(content, \"ZUPLO_PROJECT_NAME=test-project\");\n assert.include(content, \"ZUPLO_ENVIRONMENT_TYPE=development\");\n assert.include(content, \"ZUPLO_SYSTEM_CONFIGURATIONS=config-123\");\n\n // Verify public section is present with variables\n assert.include(content, \"# Public Zuplo environment variables\");\n assert.include(content, 'ZUPLO_PUBLIC_API_URL=\"https://api.example.com\"');\n assert.include(content, 'ZUPLO_PUBLIC_DOCS_URL=\"https://docs.example.com\"');\n\n // Verify user section is NOT present since there are no user variables\n assert.notInclude(\n content,\n \"# Environment variables defined in the Zuplo UI for the environment\"\n );\n\n // Clean up\n await rm(testDir, { recursive: true, force: true });\n });\n\n it(\"should only include user variables section when user variables exist\", async () => {\n const mockPayload = {\n accountName: \"test-account\",\n projectName: \"test-project\",\n environmentType: \"development\",\n systemConfigurations: \"config-123\",\n // Only user variables, no public variables\n DATABASE_URL: \"postgres://localhost:5432/db\",\n API_KEY: \"secret-key-123\",\n };\n\n // Mock successful API response\n mockAgent\n .get(TEST_API_ENDPOINT)\n .intercept({\n path: `/v1/environments/${TEST_ENVIRONMENT}/local-configurations`,\n method: \"GET\",\n headers: {\n authorization: `Bearer ${TEST_AUTH_TOKEN}`,\n },\n })\n .reply(200, mockPayload);\n\n const { pullLocalConfig } = await import(\"../common/populate.js\");\n\n await pullLocalConfig({\n dir: testDir,\n environment: TEST_ENVIRONMENT,\n authToken: TEST_AUTH_TOKEN,\n });\n\n // Read the generated file\n const envFilePath = join(testDir, \".env.zuplo\");\n const content = await readFile(envFilePath, \"utf-8\");\n\n // Verify system variables are present\n assert.include(content, \"ZUPLO_ACCOUNT_NAME=test-account\");\n assert.include(content, \"ZUPLO_PROJECT_NAME=test-project\");\n assert.include(content, \"ZUPLO_ENVIRONMENT_TYPE=development\");\n assert.include(content, \"ZUPLO_SYSTEM_CONFIGURATIONS=config-123\");\n\n // Verify public section is NOT present since there are no public variables\n assert.notInclude(content, \"# Public Zuplo environment variables\");\n\n // Verify user section is present with variables\n assert.include(\n content,\n \"# Environment variables defined in the Zuplo UI for the environment\"\n );\n assert.include(content, 'DATABASE_URL=\"postgres://localhost:5432/db\"');\n assert.include(content, 'API_KEY=\"secret-key-123\"');\n\n // Clean up\n await rm(testDir, { recursive: true, force: true });\n });\n\n it(\"should preserve quoted and multiline environment variable values\", async () => {\n const mockPayload = {\n accountName: \"test-account\",\n projectName: \"test-project\",\n environmentType: \"development\",\n systemConfigurations: \"config-123\",\n // Environment variables with double quotes that need escaping\n DATABASE_URL: \"postgres://user:p'assw'ord@localhost:5432/db\",\n API_KEY: \"secret'with'quotes\",\n JSON_CONFIG:\n '{\"message\": \"Hello \\'world\\'\", \"nested\": {\"value\": \"test\\'s\"}}',\n ZUPLO_PUBLIC_MESSAGE: \"Welcome to Zuplo's platform!\",\n COMPLEX_VALUE: \"?\\\\\\\"!##==A_special_chars'''\",\n // Additional special character test cases\n EDGE_CASE_1: \"value with 'single' and \\\"double\\\" quotes\",\n EDGE_CASE_2: \"path\\\\to\\\\file's location\",\n EDGE_CASE_3: \"it's a $pecial @#$%^&*() value!\",\n EDGE_CASE_4: \"multi\\nline\\nwith'quotes\",\n EDGE_CASE_5: \"tabs\\tand\\tspaces and 'quotes'\",\n EDGE_CASE_6:\n 'value with \"double quotes\", a `backtick`, and a literal\\\\nnewline',\n EDGE_CASE_7:\n \"value with \\\"double quotes\\\", a `backtick`, a 'single quote', and a literal\\\\nnewline\",\n CARRIAGE_RETURN: \"before\\rafter\",\n };\n\n // Mock successful API response\n mockAgent\n .get(TEST_API_ENDPOINT)\n .intercept({\n path: `/v1/environments/${TEST_ENVIRONMENT}/local-configurations`,\n method: \"GET\",\n headers: {\n authorization: `Bearer ${TEST_AUTH_TOKEN}`,\n },\n })\n .reply(200, mockPayload);\n\n const { pullLocalConfig } = await import(\"../common/populate.js\");\n\n await pullLocalConfig({\n dir: testDir,\n environment: TEST_ENVIRONMENT,\n authToken: TEST_AUTH_TOKEN,\n });\n\n // Read the generated file\n const envFilePath = join(testDir, \".env.zuplo\");\n const content = await readFile(envFilePath, \"utf-8\");\n\n // Simple values use double quotes. Values containing double quotes use\n // backticks so dotenv can parse them without changing their contents.\n assert.include(\n content,\n \"DATABASE_URL=\\\"postgres://user:p'assw'ord@localhost:5432/db\\\"\"\n );\n assert.include(content, \"API_KEY=\\\"secret'with'quotes\\\"\");\n assert.include(\n content,\n 'JSON_CONFIG=`{\"message\": \"Hello \\'world\\'\", \"nested\": {\"value\": \"test\\'s\"}}`'\n );\n assert.include(\n content,\n 'ZUPLO_PUBLIC_MESSAGE=\"Welcome to Zuplo\\'s platform!\"'\n );\n assert.include(\n content,\n \"EDGE_CASE_1=`value with 'single' and \\\"double\\\" quotes`\"\n );\n assert.include(content, `EDGE_CASE_7=${mockPayload.EDGE_CASE_7}`);\n assert.include(content, 'CARRIAGE_RETURN=\"before\\\\rafter\"');\n\n const parsedEnv = dotenvParse(content);\n for (const [key, value] of Object.entries(mockPayload)) {\n if (!SYSTEM_PAYLOAD_KEYS.includes(key)) {\n assert.equal(parsedEnv[key], value, `${key} should round trip exactly`);\n }\n }\n\n // Clean up\n await rm(testDir, { recursive: true, force: true });\n });\n});\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"populate.d.ts","sourceRoot":"","sources":["../../src/common/populate.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"populate.d.ts","sourceRoot":"","sources":["../../src/common/populate.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AA+D/C,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,KAAK,GAAG,aAAa,GAAG,WAAW,CAAC,iBAiD3D;AAUD,wBAAsB,eAAe,CACnC,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,KAAK,GAAG,aAAa,GAAG,WAAW,CAAC,iBAiH3D"}
|
package/dist/common/populate.js
CHANGED
|
@@ -11,8 +11,25 @@ const SYSTEM_KEYS = [
|
|
|
11
11
|
"systemConfigurations",
|
|
12
12
|
];
|
|
13
13
|
function wrapEnvValue(value) {
|
|
14
|
-
const
|
|
15
|
-
|
|
14
|
+
const doubleQuotesAreSafe = !value.includes('"') && !value.includes("\\n") && !value.includes("\\r");
|
|
15
|
+
if (doubleQuotesAreSafe) {
|
|
16
|
+
return `"${value.replace(/\r/g, "\\r")}"`;
|
|
17
|
+
}
|
|
18
|
+
if (!value.includes("`") && !value.includes("\r")) {
|
|
19
|
+
return `\`${value}\``;
|
|
20
|
+
}
|
|
21
|
+
if (!value.includes("'") && !value.includes("\r")) {
|
|
22
|
+
return `'${value}'`;
|
|
23
|
+
}
|
|
24
|
+
const unquotedValueIsSafe = value.trim() === value &&
|
|
25
|
+
!value.includes("#") &&
|
|
26
|
+
!value.includes("\n") &&
|
|
27
|
+
!value.includes("\r") &&
|
|
28
|
+
!/^(['"`])[\s\S]*\1$/.test(value);
|
|
29
|
+
if (unquotedValueIsSafe) {
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
32
|
+
return undefined;
|
|
16
33
|
}
|
|
17
34
|
export async function pullSystemConfig(argv) {
|
|
18
35
|
const normalizedDir = resolve(argv.dir);
|
|
@@ -69,20 +86,25 @@ export async function pullLocalConfig(argv) {
|
|
|
69
86
|
}
|
|
70
87
|
}
|
|
71
88
|
const payload = await environmentResponseFromDeveloperAPI.json();
|
|
89
|
+
const unserializableEnvVars = [];
|
|
90
|
+
const serializeEnvVar = (key) => {
|
|
91
|
+
const serializedValue = wrapEnvValue(payload[key]);
|
|
92
|
+
if (serializedValue === undefined) {
|
|
93
|
+
unserializableEnvVars.push(key);
|
|
94
|
+
return [];
|
|
95
|
+
}
|
|
96
|
+
return [`${key}=${serializedValue}`];
|
|
97
|
+
};
|
|
72
98
|
const userEnvVars = Object.keys(payload)
|
|
73
99
|
.filter((key) => {
|
|
74
100
|
return !key.startsWith("ZUPLO_PUBLIC_") && !SYSTEM_KEYS.includes(key);
|
|
75
101
|
})
|
|
76
|
-
.
|
|
77
|
-
return `${key}=${wrapEnvValue(payload[key])}`;
|
|
78
|
-
});
|
|
102
|
+
.flatMap(serializeEnvVar);
|
|
79
103
|
const zuploPublicEnvVars = Object.keys(payload)
|
|
80
104
|
.filter((key) => {
|
|
81
105
|
return key.startsWith("ZUPLO_PUBLIC_");
|
|
82
106
|
})
|
|
83
|
-
.
|
|
84
|
-
return `${key}=${wrapEnvValue(payload[key])}`;
|
|
85
|
-
});
|
|
107
|
+
.flatMap(serializeEnvVar);
|
|
86
108
|
let content = `# This file is auto-generated from zuplo link. Please do not edit it manually.
|
|
87
109
|
# It will be auto-generated afresh the next time you run zuplo link.
|
|
88
110
|
# If you wish to add your own environment variables, create a separate .env file.
|
|
@@ -101,11 +123,25 @@ ${zuploPublicEnvVars.join("\n")}`;
|
|
|
101
123
|
content += `
|
|
102
124
|
|
|
103
125
|
# Environment variables defined in the Zuplo UI for the environment
|
|
104
|
-
#
|
|
105
|
-
# will show up as \\" in the value.
|
|
126
|
+
# Values are quoted so dotenv preserves their exact contents.
|
|
106
127
|
${userEnvVars.join("\n")}`;
|
|
107
128
|
}
|
|
108
129
|
content += "\n";
|
|
109
130
|
await writeFile(zuploPreferredConfigFile, content);
|
|
131
|
+
if (unserializableEnvVars.length > 0) {
|
|
132
|
+
const variableNames = unserializableEnvVars
|
|
133
|
+
.map((key) => `"${key}"`)
|
|
134
|
+
.join(", ");
|
|
135
|
+
const hasMultipleVariables = unserializableEnvVars.length > 1;
|
|
136
|
+
const variableLabel = hasMultipleVariables ? "variables" : "variable";
|
|
137
|
+
const verb = hasMultipleVariables ? "were" : "was";
|
|
138
|
+
const reason = hasMultipleVariables
|
|
139
|
+
? "their values contain"
|
|
140
|
+
: "its value contains";
|
|
141
|
+
const omittedVariables = hasMultipleVariables
|
|
142
|
+
? "these variables"
|
|
143
|
+
: "this variable";
|
|
144
|
+
throw new Error(`Environment ${variableLabel} ${variableNames} ${verb} not written to .env.zuplo because ${reason} a combination of single quotes, double quotes, backticks, or line breaks that dotenv cannot preserve. The file was still created without ${omittedVariables}.`);
|
|
145
|
+
}
|
|
110
146
|
}
|
|
111
147
|
//# sourceMappingURL=populate.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"populate.js","sourceRoot":"","sources":["../../src/common/populate.ts"],"names":[],"mappings":"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","sourcesContent":["import { writeFile } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\nimport { Arguments } from \"../link/handler.js\";\nimport { ZUPLO_SYSTEM_ENV_VAR } from \"./constants.js\";\nimport { logger } from \"./logger.js\";\nimport { printCriticalFailureToConsoleAndExit } from \"./output.js\";\nimport settings from \"./settings.js\";\n\nconst SYSTEM_KEYS = [\n \"accountName\",\n \"projectName\",\n \"environmentType\",\n \"systemConfigurations\",\n];\n\n/**\n * Wraps environment variable values in double quotes for dotenv compatibility.\n * Escapes any double quotes within the value by replacing them with \\\".\n * This ensures proper parsing while preserving special characters.\n *\n * @param value The environment variable value to wrap\n * @returns The value wrapped in double quotes with escaped double quotes\n */\nfunction wrapEnvValue(value: string): string {\n // Escape double quotes by replacing them with \\\"\n const escapedValue = value.replace(/\"/g, '\\\\\"');\n // Always use double quotes\n return `\"${escapedValue}\"`;\n}\n\n/**\n * Pulls the system configuration from the API and writes it to the .env.zuplo file.\n * All the system environment variables are encoded in base58. Use this wherever\n * we need to *make sure* that the system environment variables are preserved correctly,\n * e.g in deployments.\n * @param argv\n */\nexport async function pullSystemConfig(\n argv: Pick<Arguments, \"dir\" | \"environment\" | \"authToken\">\n) {\n const normalizedDir = resolve(argv.dir);\n const zuploPreferredConfigFile = join(normalizedDir, ZUPLO_SYSTEM_ENV_VAR);\n\n const environmentResponseFromDeveloperAPI = await fetch(\n `${settings.ZUPLO_DEVELOPER_API_ENDPOINT}/v1/environments/${argv.environment}/configurations`,\n {\n headers: {\n authorization: `Bearer ${argv.authToken}`,\n },\n }\n );\n\n if (!environmentResponseFromDeveloperAPI.ok) {\n if (\n environmentResponseFromDeveloperAPI.status === 404 ||\n environmentResponseFromDeveloperAPI.status === 401\n ) {\n await printCriticalFailureToConsoleAndExit(\n \"Error: Failed to link data from the environment. The environment you specified doesn't exist or you don't have access to it.\"\n );\n } else {\n logger.error(\n {\n status: environmentResponseFromDeveloperAPI.status,\n statusText: environmentResponseFromDeveloperAPI.statusText,\n },\n `Failed to link data from ${argv.environment}`\n );\n await printCriticalFailureToConsoleAndExit(\n \"Error: Failed to link data from the environment. Please try again later.\"\n );\n }\n }\n\n const payload = await environmentResponseFromDeveloperAPI.json();\n\n const content = `\n# This file is auto-generated from zuplo link. Please do not edit it manually.\n# It will be auto-generated afresh the next time you run zuplo link.\n# If you wish to add your own environment variables, create a separate .env file.\nZUPLO_ACCOUNT_NAME=${payload.accountName}\nZUPLO_PROJECT_NAME=${payload.projectName}\nZUPLO_ENVIRONMENT_TYPE=${payload.environmentType}\nZUPLO_SYSTEM_CONFIGURATIONS=${payload[\"systemConfigurations\"]}\n`;\n\n await writeFile(zuploPreferredConfigFile, content);\n}\n\n/**\n * Pulls the local configuration from dev-api and writes it to the .env.zuplo file.\n * This method differs from pullSystemConfig in that it writes the user defined\n * environment variables, as well as the public variables explicitly to the\n * file instead of getting all variable in the base58 encoded ZUPLO_SYSTEM_CONFIGURATIONS\n * variable.\n * @param argv\n */\nexport async function pullLocalConfig(\n argv: Pick<Arguments, \"dir\" | \"environment\" | \"authToken\">\n) {\n const normalizedDir = resolve(argv.dir);\n const zuploPreferredConfigFile = join(normalizedDir, ZUPLO_SYSTEM_ENV_VAR);\n\n const environmentResponseFromDeveloperAPI = await fetch(\n `${settings.ZUPLO_DEVELOPER_API_ENDPOINT}/v1/environments/${argv.environment}/local-configurations`,\n {\n headers: {\n authorization: `Bearer ${argv.authToken}`,\n },\n }\n );\n\n if (!environmentResponseFromDeveloperAPI.ok) {\n if (\n environmentResponseFromDeveloperAPI.status === 404 ||\n environmentResponseFromDeveloperAPI.status === 401\n ) {\n await printCriticalFailureToConsoleAndExit(\n \"Error: Failed to link data from the environment. The environment you specified doesn't exist or you don't have access to it.\"\n );\n } else {\n logger.error(\n {\n status: environmentResponseFromDeveloperAPI.status,\n statusText: environmentResponseFromDeveloperAPI.statusText,\n },\n `Failed to link data from ${argv.environment}`\n );\n await printCriticalFailureToConsoleAndExit(\n \"Error: Failed to link data from the environment. Please try again later.\"\n );\n }\n }\n\n const payload = await environmentResponseFromDeveloperAPI.json();\n\n // We wrap the env vars in appropriate quotes to preserve special characters\n // and handle single quotes properly for dotenv parsing.\n const userEnvVars = Object.keys(payload)\n .filter((key) => {\n return !key.startsWith(\"ZUPLO_PUBLIC_\") && !SYSTEM_KEYS.includes(key);\n })\n .map((key) => {\n return `${key}=${wrapEnvValue(payload[key])}`;\n });\n\n const zuploPublicEnvVars = Object.keys(payload)\n .filter((key) => {\n // These start with ZUPLO_PUBLIC_ and are not system variables\n return key.startsWith(\"ZUPLO_PUBLIC_\");\n })\n .map((key) => {\n return `${key}=${wrapEnvValue(payload[key])}`;\n });\n\n let content = `# This file is auto-generated from zuplo link. Please do not edit it manually.\n# It will be auto-generated afresh the next time you run zuplo link.\n# If you wish to add your own environment variables, create a separate .env file.\n\nZUPLO_ACCOUNT_NAME=${payload.accountName}\nZUPLO_PROJECT_NAME=${payload.projectName}\nZUPLO_ENVIRONMENT_TYPE=${payload.environmentType}\nZUPLO_SYSTEM_CONFIGURATIONS=${payload[\"systemConfigurations\"]}`;\n\n // Only add public environment variables section if there are any\n if (zuploPublicEnvVars.length > 0) {\n content += `\n\n# Public Zuplo environment variables\n${zuploPublicEnvVars.join(\"\\n\")}`;\n }\n\n // Only add user environment variables section if there are any\n if (userEnvVars.length > 0) {\n content += `\n\n# Environment variables defined in the Zuplo UI for the environment\n# Note that \" characters are escaped with a backslash and escaped double quotes\n# will show up as \\\\\" in the value.\n${userEnvVars.join(\"\\n\")}`;\n }\n\n // Add final newline\n content += \"\\n\";\n\n await writeFile(zuploPreferredConfigFile, content);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"populate.js","sourceRoot":"","sources":["../../src/common/populate.ts"],"names":[],"mappings":"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","sourcesContent":["import { writeFile } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\nimport { Arguments } from \"../link/handler.js\";\nimport { ZUPLO_SYSTEM_ENV_VAR } from \"./constants.js\";\nimport { logger } from \"./logger.js\";\nimport { printCriticalFailureToConsoleAndExit } from \"./output.js\";\nimport settings from \"./settings.js\";\n\nconst SYSTEM_KEYS = [\n \"accountName\",\n \"projectName\",\n \"environmentType\",\n \"systemConfigurations\",\n];\n\n/**\n * Serializes an environment variable value without changing what dotenv parses.\n * Prefers quoted forms, then falls back to unquoted output when dotenv can\n * preserve it exactly.\n *\n * @param value The environment variable value to serialize\n * @returns A value that dotenv parses back to the original string, or\n * undefined when dotenv cannot preserve the value\n */\nfunction wrapEnvValue(value: string): string | undefined {\n const doubleQuotesAreSafe =\n !value.includes('\"') && !value.includes(\"\\\\n\") && !value.includes(\"\\\\r\");\n\n if (doubleQuotesAreSafe) {\n // dotenv normalizes physical carriage returns before parsing. Represent\n // them as escapes so its double-quote expansion restores the original.\n return `\"${value.replace(/\\r/g, \"\\\\r\")}\"`;\n }\n\n // dotenv normalizes physical carriage returns before it selects a quote\n // delimiter, so only its double-quoted branch can restore them exactly.\n if (!value.includes(\"`\") && !value.includes(\"\\r\")) {\n return `\\`${value}\\``;\n }\n\n if (!value.includes(\"'\") && !value.includes(\"\\r\")) {\n return `'${value}'`;\n }\n\n const unquotedValueIsSafe =\n value.trim() === value &&\n !value.includes(\"#\") &&\n !value.includes(\"\\n\") &&\n !value.includes(\"\\r\") &&\n !/^(['\"`])[\\s\\S]*\\1$/.test(value);\n\n if (unquotedValueIsSafe) {\n return value;\n }\n\n return undefined;\n}\n\n/**\n * Pulls the system configuration from the API and writes it to the .env.zuplo file.\n * All the system environment variables are encoded in base58. Use this wherever\n * we need to *make sure* that the system environment variables are preserved correctly,\n * e.g in deployments.\n * @param argv\n */\nexport async function pullSystemConfig(\n argv: Pick<Arguments, \"dir\" | \"environment\" | \"authToken\">\n) {\n const normalizedDir = resolve(argv.dir);\n const zuploPreferredConfigFile = join(normalizedDir, ZUPLO_SYSTEM_ENV_VAR);\n\n const environmentResponseFromDeveloperAPI = await fetch(\n `${settings.ZUPLO_DEVELOPER_API_ENDPOINT}/v1/environments/${argv.environment}/configurations`,\n {\n headers: {\n authorization: `Bearer ${argv.authToken}`,\n },\n }\n );\n\n if (!environmentResponseFromDeveloperAPI.ok) {\n if (\n environmentResponseFromDeveloperAPI.status === 404 ||\n environmentResponseFromDeveloperAPI.status === 401\n ) {\n await printCriticalFailureToConsoleAndExit(\n \"Error: Failed to link data from the environment. The environment you specified doesn't exist or you don't have access to it.\"\n );\n } else {\n logger.error(\n {\n status: environmentResponseFromDeveloperAPI.status,\n statusText: environmentResponseFromDeveloperAPI.statusText,\n },\n `Failed to link data from ${argv.environment}`\n );\n await printCriticalFailureToConsoleAndExit(\n \"Error: Failed to link data from the environment. Please try again later.\"\n );\n }\n }\n\n const payload = await environmentResponseFromDeveloperAPI.json();\n\n const content = `\n# This file is auto-generated from zuplo link. Please do not edit it manually.\n# It will be auto-generated afresh the next time you run zuplo link.\n# If you wish to add your own environment variables, create a separate .env file.\nZUPLO_ACCOUNT_NAME=${payload.accountName}\nZUPLO_PROJECT_NAME=${payload.projectName}\nZUPLO_ENVIRONMENT_TYPE=${payload.environmentType}\nZUPLO_SYSTEM_CONFIGURATIONS=${payload[\"systemConfigurations\"]}\n`;\n\n await writeFile(zuploPreferredConfigFile, content);\n}\n\n/**\n * Pulls the local configuration from dev-api and writes it to the .env.zuplo file.\n * This method differs from pullSystemConfig in that it writes the user defined\n * environment variables, as well as the public variables explicitly to the\n * file instead of getting all variable in the base58 encoded ZUPLO_SYSTEM_CONFIGURATIONS\n * variable.\n * @param argv\n */\nexport async function pullLocalConfig(\n argv: Pick<Arguments, \"dir\" | \"environment\" | \"authToken\">\n) {\n const normalizedDir = resolve(argv.dir);\n const zuploPreferredConfigFile = join(normalizedDir, ZUPLO_SYSTEM_ENV_VAR);\n\n const environmentResponseFromDeveloperAPI = await fetch(\n `${settings.ZUPLO_DEVELOPER_API_ENDPOINT}/v1/environments/${argv.environment}/local-configurations`,\n {\n headers: {\n authorization: `Bearer ${argv.authToken}`,\n },\n }\n );\n\n if (!environmentResponseFromDeveloperAPI.ok) {\n if (\n environmentResponseFromDeveloperAPI.status === 404 ||\n environmentResponseFromDeveloperAPI.status === 401\n ) {\n await printCriticalFailureToConsoleAndExit(\n \"Error: Failed to link data from the environment. The environment you specified doesn't exist or you don't have access to it.\"\n );\n } else {\n logger.error(\n {\n status: environmentResponseFromDeveloperAPI.status,\n statusText: environmentResponseFromDeveloperAPI.statusText,\n },\n `Failed to link data from ${argv.environment}`\n );\n await printCriticalFailureToConsoleAndExit(\n \"Error: Failed to link data from the environment. Please try again later.\"\n );\n }\n }\n\n const payload = await environmentResponseFromDeveloperAPI.json();\n const unserializableEnvVars: string[] = [];\n\n const serializeEnvVar = (key: string): string[] => {\n const serializedValue = wrapEnvValue(payload[key]);\n\n if (serializedValue === undefined) {\n unserializableEnvVars.push(key);\n return [];\n }\n\n return [`${key}=${serializedValue}`];\n };\n\n // We wrap the env vars in appropriate quotes to preserve special characters\n // and handle single quotes properly for dotenv parsing.\n const userEnvVars = Object.keys(payload)\n .filter((key) => {\n return !key.startsWith(\"ZUPLO_PUBLIC_\") && !SYSTEM_KEYS.includes(key);\n })\n .flatMap(serializeEnvVar);\n\n const zuploPublicEnvVars = Object.keys(payload)\n .filter((key) => {\n // These start with ZUPLO_PUBLIC_ and are not system variables\n return key.startsWith(\"ZUPLO_PUBLIC_\");\n })\n .flatMap(serializeEnvVar);\n\n let content = `# This file is auto-generated from zuplo link. Please do not edit it manually.\n# It will be auto-generated afresh the next time you run zuplo link.\n# If you wish to add your own environment variables, create a separate .env file.\n\nZUPLO_ACCOUNT_NAME=${payload.accountName}\nZUPLO_PROJECT_NAME=${payload.projectName}\nZUPLO_ENVIRONMENT_TYPE=${payload.environmentType}\nZUPLO_SYSTEM_CONFIGURATIONS=${payload[\"systemConfigurations\"]}`;\n\n // Only add public environment variables section if there are any\n if (zuploPublicEnvVars.length > 0) {\n content += `\n\n# Public Zuplo environment variables\n${zuploPublicEnvVars.join(\"\\n\")}`;\n }\n\n // Only add user environment variables section if there are any\n if (userEnvVars.length > 0) {\n content += `\n\n# Environment variables defined in the Zuplo UI for the environment\n# Values are quoted so dotenv preserves their exact contents.\n${userEnvVars.join(\"\\n\")}`;\n }\n\n // Add final newline\n content += \"\\n\";\n\n await writeFile(zuploPreferredConfigFile, content);\n\n if (unserializableEnvVars.length > 0) {\n const variableNames = unserializableEnvVars\n .map((key) => `\"${key}\"`)\n .join(\", \");\n const hasMultipleVariables = unserializableEnvVars.length > 1;\n const variableLabel = hasMultipleVariables ? \"variables\" : \"variable\";\n const verb = hasMultipleVariables ? \"were\" : \"was\";\n const reason = hasMultipleVariables\n ? \"their values contain\"\n : \"its value contains\";\n const omittedVariables = hasMultipleVariables\n ? \"these variables\"\n : \"this variable\";\n throw new Error(\n `Environment ${variableLabel} ${variableNames} ${verb} not written to .env.zuplo because ${reason} a combination of single quotes, double quotes, backticks, or line breaks that dotenv cannot preserve. The file was still created without ${omittedVariables}.`\n );\n }\n}\n"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inquirer/ansi",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.8",
|
|
4
4
|
"keywords": [
|
|
5
5
|
"ansi",
|
|
6
6
|
"answer",
|
|
@@ -67,6 +67,7 @@
|
|
|
67
67
|
"tsc": "tsc"
|
|
68
68
|
},
|
|
69
69
|
"devDependencies": {
|
|
70
|
+
"@repo/tsconfig": "0.0.0",
|
|
70
71
|
"typescript": "^6.0.2"
|
|
71
72
|
},
|
|
72
73
|
"engines": {
|
|
@@ -74,5 +75,5 @@
|
|
|
74
75
|
},
|
|
75
76
|
"main": "./dist/index.js",
|
|
76
77
|
"types": "./dist/index.d.ts",
|
|
77
|
-
"gitHead": "
|
|
78
|
+
"gitHead": "5748bd9966b5e175ddf5995ee4cdce6f60c4272e"
|
|
78
79
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inquirer/checkbox",
|
|
3
|
-
"version": "5.2.
|
|
3
|
+
"version": "5.2.4",
|
|
4
4
|
"description": "Inquirer checkbox prompt",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"answer",
|
|
@@ -67,10 +67,10 @@
|
|
|
67
67
|
"tsc": "tsc"
|
|
68
68
|
},
|
|
69
69
|
"dependencies": {
|
|
70
|
-
"@inquirer/ansi": "^2.0.
|
|
71
|
-
"@inquirer/core": "^12.0.
|
|
72
|
-
"@inquirer/figures": "^2.0.
|
|
73
|
-
"@inquirer/type": "
|
|
70
|
+
"@inquirer/ansi": "^2.0.8",
|
|
71
|
+
"@inquirer/core": "^12.0.2",
|
|
72
|
+
"@inquirer/figures": "^2.0.9",
|
|
73
|
+
"@inquirer/type": "4.1.1"
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|
|
76
76
|
"@repo/tsconfig": "0.0.0",
|
|
@@ -89,5 +89,5 @@
|
|
|
89
89
|
},
|
|
90
90
|
"main": "./dist/index.js",
|
|
91
91
|
"types": "./dist/index.d.ts",
|
|
92
|
-
"gitHead": "
|
|
92
|
+
"gitHead": "5748bd9966b5e175ddf5995ee4cdce6f60c4272e"
|
|
93
93
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inquirer/confirm",
|
|
3
|
-
"version": "6.3.
|
|
3
|
+
"version": "6.3.1",
|
|
4
4
|
"description": "Inquirer confirm prompt",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"answer",
|
|
@@ -67,8 +67,8 @@
|
|
|
67
67
|
"tsc": "tsc"
|
|
68
68
|
},
|
|
69
69
|
"dependencies": {
|
|
70
|
-
"@inquirer/core": "^12.0.
|
|
71
|
-
"@inquirer/type": "
|
|
70
|
+
"@inquirer/core": "^12.0.2",
|
|
71
|
+
"@inquirer/type": "4.1.1"
|
|
72
72
|
},
|
|
73
73
|
"devDependencies": {
|
|
74
74
|
"@repo/tsconfig": "0.0.0",
|
|
@@ -87,5 +87,5 @@
|
|
|
87
87
|
},
|
|
88
88
|
"main": "./dist/index.js",
|
|
89
89
|
"types": "./dist/index.d.ts",
|
|
90
|
-
"gitHead": "
|
|
90
|
+
"gitHead": "5748bd9966b5e175ddf5995ee4cdce6f60c4272e"
|
|
91
91
|
}
|