@@ -4,6 +4,7 @@ import os from "node:os";
|
4 | 4 | import path from "node:path"; |
5 | 5 | import { afterEach, describe, expect, it, vi } from "vitest"; |
6 | 6 | import { listOpenFileDescriptorsForPath } from "../infra/open-file-descriptors.test-support.js"; |
| 7 | +import { resolveSqliteDatabaseFilePaths } from "../infra/sqlite-files.js"; |
7 | 8 | import { |
8 | 9 | acquireDebugProxyCaptureStore, |
9 | 10 | closeDebugProxyCaptureStore, |
@@ -31,6 +32,10 @@ function makeStore() {
|
31 | 32 | return new DebugProxyCaptureStore(path.join(root, "capture.sqlite"), path.join(root, "blobs")); |
32 | 33 | } |
33 | 34 | |
| 35 | +function readMode(target: string): number { |
| 36 | +return fs.statSync(target).mode & 0o777; |
| 37 | +} |
| 38 | + |
34 | 39 | describe("DebugProxyCaptureStore", () => { |
35 | 40 | it.runIf(process.platform === "linux")("closes the database when initialization fails", () => { |
36 | 41 | const root = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-proxy-capture-failed-open-")); |
@@ -112,6 +117,32 @@ describe("DebugProxyCaptureStore", () => {
|
112 | 117 | } |
113 | 118 | }); |
114 | 119 | |
| 120 | +it.runIf(process.platform !== "win32")("keeps capture databases and blobs private", () => { |
| 121 | +const root = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-proxy-capture-permissions-")); |
| 122 | +cleanupDirs.push(root); |
| 123 | +const dbDir = path.join(root, "db"); |
| 124 | +const dbPath = path.join(dbDir, "capture.sqlite"); |
| 125 | +const blobDir = path.join(root, "blobs"); |
| 126 | +const store = new DebugProxyCaptureStore(dbPath, blobDir); |
| 127 | +const blob = store.persistPayload(Buffer.from("authorization: Bearer secret")); |
| 128 | + |
| 129 | +expect(readMode(dbDir)).toBe(0o700); |
| 130 | +expect(readMode(blobDir)).toBe(0o700); |
| 131 | +for (const databaseFile of resolveSqliteDatabaseFilePaths(dbPath).filter(fs.existsSync)) { |
| 132 | +expect(readMode(databaseFile)).toBe(0o600); |
| 133 | +} |
| 134 | +expect(readMode(blob.path)).toBe(0o600); |
| 135 | + |
| 136 | +store.close(); |
| 137 | +fs.chmodSync(dbPath, 0o644); |
| 138 | +fs.chmodSync(blob.path, 0o644); |
| 139 | +const reopened = new DebugProxyCaptureStore(dbPath, blobDir); |
| 140 | +reopened.persistPayload(Buffer.from("authorization: Bearer secret")); |
| 141 | +expect(readMode(dbPath)).toBe(0o600); |
| 142 | +expect(readMode(blob.path)).toBe(0o600); |
| 143 | +reopened.close(); |
| 144 | +}); |
| 145 | + |
115 | 146 | it("ignores duplicate close calls", () => { |
116 | 147 | const store = makeStore(); |
117 | 148 | |
|