Keep owned Docker database credentials in server-only environment

This commit is contained in:
Dotta committed 2026-10-27 02:11:39 -05:00
1 parent 1454f54399
commit 96058c7e2f
6 files changed
+51 -9

No files matched your search

+38 -2
View File
@@ -9,7 +9,9 @@ import { assertRunnerDatabaseIsolation, assertEmbeddedDatabaseIsolation } from "
import { campaignDatabaseEvidenceEligible, type CampaignAttempt } from "./chat-campaign.js";
import { assertChatCatalogFingerprintLane, fingerprintChatDependencyClosure } from "./chat-catalog-fingerprint.js";
import { validateRetainedRunnerResult } from "./result-validation.js";
import { buildPaperclipServerEnvironment } from "./harness-env.js";
import { assertIsolatedServerEnvironment, buildPaperclipServerEnvironment } from "./harness-env.js";
import { findSecretLeakInDirectory } from "./redaction.js";
import { createSanitizedCodexEnvironment } from "../../packages/paperclip-runner/src/drivers/codex/app-server-transport.js";
const roots: string[] = [];
beforeEach(() => { vi.stubEnv("DOCKER_HOST", ""); vi.stubEnv("DOCKER_CONTEXT", ""); });
afterEach(async () => { vi.unstubAllEnvs(); for (const root of roots.splice(0)) await rm(root, { recursive: true, force: true }); });
@@ -71,7 +73,10 @@ it("binds exact image/engine/resources, strips admission data and removes only o
expect(supervisor.source[DOCKER_DATABASE_ENV]).toBeUndefined(); expect(supervisor.source[DATABASE_LANE_ENV]).toBeUndefined();
const configPath = path.join(temp, "paperclip-home", "instances", "fixture", "config.json");
expect(await prepareRunnerE2EServerConfig({ temporaryRoot: temp, configPath, serverPort: 3100, dockerReceiptPath: owned.filename, dockerRun: run })).toBeNull();
const config = JSON.parse(await readFile(configPath, "utf8")); expect(config.database.mode).toBe("postgres"); expect(config.database.connectionString).toBe(owned.receipt.connectionString);
const config = JSON.parse(await readFile(configPath, "utf8")); expect(config.database.mode).toBe("postgres"); expect(config.database.connectionString).toBeUndefined();
expect(JSON.stringify(config)).not.toContain(secrets[0]);
expect(supervisor.serverOverrides.DATABASE_URL).toBe(owned.receipt.connectionString);
expect(supervisor.source.DATABASE_URL).toBeUndefined();
const key = config.secrets.localEncrypted.keyFilePath; await mkdir(path.dirname(key), { recursive: true }); await writeFile(key, "offline-key", { mode: 0o600 });
await expect(assertRunnerDatabaseIsolation(configPath, temp, owned.filename, run)).resolves.toBeUndefined();
const changed = structuredClone(config); changed.database.connectionString = "postgresql://foreign"; await writeFile(configPath, JSON.stringify(changed), { mode: 0o600 });
@@ -183,3 +188,34 @@ it("allows only exact Docker Desktop host translation with an owned canonical pr
await rm(password); await writeFile(password, contents, { mode: 0o600 });
await owned.close(); expect(state.container).toBeNull(); expect(state.volume).toBeNull();
});
it("keeps owned DB credentials server-only without any persisted scan exemption", async () => {
const temp = await root(), { run } = daemon(), secrets: string[] = [];
const owned = await startOwnedDockerDatabase({ temporaryRoot: temp, privateSecrets: secrets, run });
const admission = await dockerDatabaseSupervisorEnvironment({ temporaryRoot: temp, env: { [DATABASE_LANE_ENV]: "owned-docker-postgres", [DOCKER_DATABASE_ENV]: owned.filename, DATABASE_URL: "ambient-unrelated", DATABASE_MIGRATION_URL: "ambient-migration" }, run });
const home = path.join(temp, "paperclip-home"), configPath = path.join(home, "instances", "custody", "config.json");
await prepareRunnerE2EServerConfig({ temporaryRoot: temp, configPath, serverPort: 3100, dockerReceiptPath: owned.filename, dockerRun: run });
const expected = { temporaryRoot: temp, paperclipHome: home, configPath, ownedDatabaseUrl: admission.serverOverrides.DATABASE_URL };
const env = buildPaperclipServerEnvironment(admission.source, { ...admission.serverOverrides, PAPERCLIP_HOME: home, PAPERCLIP_CONFIG: configPath, XDG_CACHE_HOME: path.join(temp, "xdg-cache"), PAPERCLIP_AGENT_JWT_SECRET: "jwt", PAPERCLIP_DECISION_SIGNING_SECRET: "decision", PAPERCLIP_TOOL_ACTION_SIGNING_SECRET: "tool", BETTER_AUTH_SECRET: "auth" });
expect(env.DATABASE_URL).toBe(owned.receipt.connectionString);
expect(env.DATABASE_MIGRATION_URL).toBeUndefined();
expect(() => assertIsolatedServerEnvironment(env, expected)).not.toThrow();
expect(() => assertIsolatedServerEnvironment({ ...env, DATABASE_URL: "ambient-unrelated" }, expected)).toThrow();
expect(() => assertIsolatedServerEnvironment(env, { ...expected, ownedDatabaseUrl: undefined })).toThrow();
expect(createSanitizedCodexEnvironment(env).DATABASE_URL).toBeUndefined();
expect(createSanitizedCodexEnvironment(env).DATABASE_MIGRATION_URL).toBeUndefined();
expect(await findSecretLeakInDirectory(home, secrets, { includeShapes: false })).toBeNull();
const config = JSON.parse(await readFile(configPath, "utf8"));
config.database.connectionString = owned.receipt.connectionString;
await writeFile(configPath, JSON.stringify(config), { mode: 0o600 });
expect(await findSecretLeakInDirectory(home, secrets, { includeShapes: false })).not.toBeNull();
await expect(prepareRunnerE2EServerConfig({ temporaryRoot: temp, configPath, serverPort: 3100, dockerReceiptPath: owned.filename, dockerRun: run })).rejects.toThrow("differs");
delete config.database.connectionString;
config.unrelatedField = secrets[0];
await writeFile(configPath, JSON.stringify(config), { mode: 0o600 });
expect(await findSecretLeakInDirectory(home, secrets, { includeShapes: false })).not.toBeNull();
config.unrelatedField = "provider-secret-canary";
await writeFile(configPath, JSON.stringify(config), { mode: 0o600 });
expect(await findSecretLeakInDirectory(home, [...secrets, "provider-secret-canary"], { includeShapes: false })).not.toBeNull();
await owned.close();
});