From f7cc29274212b66b7d1aca19a07ad2f9a72f0dae Mon Sep 17 00:00:00 2001 From: Dotta Date: Wed, 11 Mar 2026 16:38:31 -0500 Subject: [PATCH] Fix env-sensitive worktree and runtime config tests Co-Authored-By: Paperclip --- cli/src/__tests__/worktree.test.ts | 16 +++++++++++++++- cli/src/commands/worktree.ts | 13 +++++++++++-- packages/db/src/runtime-config.test.ts | 1 + 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/cli/src/__tests__/worktree.test.ts b/cli/src/__tests__/worktree.test.ts index 8493f897..9787eaf1 100644 --- a/cli/src/__tests__/worktree.test.ts +++ b/cli/src/__tests__/worktree.test.ts @@ -2,7 +2,7 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; import { execFileSync } from "node:child_process"; -import { describe, expect, it } from "vitest"; +import { afterEach, describe, expect, it } from "vitest"; import { copyGitHooksToWorktreeGitDir, copySeededSecretsKey, @@ -22,6 +22,20 @@ import { } from "../commands/worktree-lib.js"; import type { PaperclipConfig } from "../config/schema.js"; +const ORIGINAL_CWD = process.cwd(); +const ORIGINAL_ENV = { ...process.env }; + +afterEach(() => { + process.chdir(ORIGINAL_CWD); + for (const key of Object.keys(process.env)) { + if (!(key in ORIGINAL_ENV)) delete process.env[key]; + } + for (const [key, value] of Object.entries(ORIGINAL_ENV)) { + if (value === undefined) delete process.env[key]; + else process.env[key] = value; + } +}); + function buildSourceConfig(): PaperclipConfig { return { $meta: { diff --git a/cli/src/commands/worktree.ts b/cli/src/commands/worktree.ts index 8781b008..b1f9b0ec 100644 --- a/cli/src/commands/worktree.ts +++ b/cli/src/commands/worktree.ts @@ -119,6 +119,14 @@ function nonEmpty(value: string | null | undefined): string | null { return typeof value === "string" && value.trim().length > 0 ? value.trim() : null; } +function isCurrentSourceConfigPath(sourceConfigPath: string): boolean { + const currentConfigPath = process.env.PAPERCLIP_CONFIG; + if (!currentConfigPath || currentConfigPath.trim().length === 0) { + return false; + } + return path.resolve(currentConfigPath) === path.resolve(sourceConfigPath); +} + function resolveWorktreeMakeName(name: string): string { const value = nonEmpty(name); if (!value) { @@ -440,9 +448,10 @@ export function copySeededSecretsKey(input: { mkdirSync(path.dirname(input.targetKeyFilePath), { recursive: true }); + const allowProcessEnvFallback = isCurrentSourceConfigPath(input.sourceConfigPath); const sourceInlineMasterKey = nonEmpty(input.sourceEnvEntries.PAPERCLIP_SECRETS_MASTER_KEY) ?? - nonEmpty(process.env.PAPERCLIP_SECRETS_MASTER_KEY); + (allowProcessEnvFallback ? nonEmpty(process.env.PAPERCLIP_SECRETS_MASTER_KEY) : null); if (sourceInlineMasterKey) { writeFileSync(input.targetKeyFilePath, sourceInlineMasterKey, { encoding: "utf8", @@ -458,7 +467,7 @@ export function copySeededSecretsKey(input: { const sourceKeyFileOverride = nonEmpty(input.sourceEnvEntries.PAPERCLIP_SECRETS_MASTER_KEY_FILE) ?? - nonEmpty(process.env.PAPERCLIP_SECRETS_MASTER_KEY_FILE); + (allowProcessEnvFallback ? nonEmpty(process.env.PAPERCLIP_SECRETS_MASTER_KEY_FILE) : null); const sourceConfiguredKeyPath = sourceKeyFileOverride ?? input.sourceConfig.secrets.localEncrypted.keyFilePath; const sourceKeyFilePath = resolveRuntimeLikePath(sourceConfiguredKeyPath, input.sourceConfigPath); diff --git a/packages/db/src/runtime-config.test.ts b/packages/db/src/runtime-config.test.ts index 55371e09..4627e691 100644 --- a/packages/db/src/runtime-config.test.ts +++ b/packages/db/src/runtime-config.test.ts @@ -46,6 +46,7 @@ describe("resolveDatabaseTarget", () => { const projectDir = path.join(tempDir, "repo"); fs.mkdirSync(projectDir, { recursive: true }); process.chdir(projectDir); + delete process.env.PAPERCLIP_CONFIG; writeJson(path.join(projectDir, ".paperclip", "config.json"), { database: { mode: "embedded-postgres", embeddedPostgresPort: 54329 }, });