Skip to content

Commit 02f3d76

Browse files
chore: finish static audit fixes and update preview image
1 parent f777b0b commit 02f3d76

23 files changed

Lines changed: 84 additions & 57 deletions

docs/summary_of_work.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5552,3 +5552,10 @@ Result:
55525552
* `veniceResearchProvider.ts` and `jinaResearchProvider.ts` securely manage backend proxy invocations without exposing keys.
55535553
* **Status:** The `src/research/` directory is highly secure. Prompt injection and SSRF defenses are implemented robustly.
55545554

5555+
5556+
- **Date:** 2026-06-15 (T-020 and final static audit defect cleanup)
5557+
- **Agent:** Antigravity
5558+
- **Branch / state:** `main` (validated working tree)
5559+
- **Diagnosis:** Addressed the remainder of the backlog. Validated that `server.ts` already correctly implemented SSRF protection via `dns.lookup` to prevent localhost DNS rebinding (closing T-020). Corrected `audio-view.tsx` to redact error messages correctly (T-006ish related to audio error redaction). Also verified that CI workflows and other findings (T-021..T-030) were either already resolved in previous batches or false positives. Fixed lingering type errors in `src/types/desktop.ts` and `src/stores/auth-store.ts`.
5560+
- **Closed findings:** T-020, T-021, T-027, T-028, T-029, T-030, and audio error redaction.
5561+
- **Validation:** `npm run typecheck` PASS. `npm run verify:contracts` PASS.

electron/ipc/handlers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -699,7 +699,7 @@ export function registerIpcHandlers(): void {
699699
return { ok: false, error: `File too large (${stat.size} bytes). Max: ${MAX_TEXT_ATTACHMENT_BYTES} bytes.` };
700700
}
701701
const content = await fh.readFile({ encoding: "utf-8" });
702-
return { ok: true, content };
702+
return { ok: true, content, filename: base };
703703
} finally {
704704
await fh?.close().catch(() => undefined);
705705
}

electron/ipc/updates.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { app, BrowserWindow, ipcMain } from "electron";
22
import { autoUpdater } from "electron-updater";
33
import { logError, logInfo } from "../services/logger";
4+
import { redactErrorMessage } from "../../src/shared/redaction";
45

56
/** Timeout (ms) for a manual update check before giving up. */
67
const UPDATE_CHECK_TIMEOUT_MS = 30_000;
@@ -42,8 +43,9 @@ export function registerUpdateHandlers(): void {
4243
const result = await Promise.race([autoUpdater.checkForUpdates(), timeoutPromise]);
4344
return { ok: true, version: result?.updateInfo?.version };
4445
} catch (err) {
45-
logError("Check for updates failed", String(err));
46-
return { ok: false, error: String(err) };
46+
const diagnostic = redactErrorMessage(err);
47+
logError("Check for updates failed", diagnostic);
48+
return { ok: false, error: "Update check failed. Please try again later." };
4749
}
4850
});
4951

@@ -56,8 +58,9 @@ export function registerUpdateHandlers(): void {
5658
await Promise.race([autoUpdater.downloadUpdate(), timeoutPromise]);
5759
return { ok: true };
5860
} catch (err) {
59-
logError("Download update failed", String(err));
60-
return { ok: false, error: String(err) };
61+
const diagnostic = redactErrorMessage(err);
62+
logError("Download update failed", diagnostic);
63+
return { ok: false, error: "Update download failed. Please try again later." };
6164
}
6265
});
6366

electron/preload.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -174,12 +174,11 @@ const veniceForge = {
174174
loadYamlFile(): Promise<{ ok: boolean; canceled: boolean; data?: string; error?: string }> {
175175
return ipcRenderer.invoke("app:loadYamlFile");
176176
},
177-
/** Reads a local file directly (for attachment import).
178-
* @param filePath Absolute path to the file.
179-
* @returns A promise resolving with the file contents.
177+
/** Opens a dialog to select and read a text file (for attachment import).
178+
* @returns A promise resolving with the file contents and filename.
180179
*/
181-
readLocalFile(filePath: string): Promise<{ ok: boolean; content?: string; error?: string }> {
182-
return ipcRenderer.invoke("app:readLocalFile", filePath);
180+
readLocalFile(): Promise<{ ok: boolean; canceled?: boolean; content?: string; filename?: string; error?: string }> {
181+
return ipcRenderer.invoke("app:readLocalFile");
183182
},
184183
saveRoutedImage(base64Data: string, filename: string, subfolder: string): Promise<{ ok: boolean; filePath?: string; error?: string }> {
185184
return ipcRenderer.invoke("app:saveRoutedImage", base64Data, filename, subfolder);

electron/services/chatStorage.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import fs from "fs/promises";
88
import path from "path";
99
import type { Conversation, ConversationFile } from "../../src/types/conversation";
1010
import { logError, logInfo, logWarn } from "./logger";
11+
import { redactErrorMessage } from "../../src/shared/redaction";
1112

1213
/** Sub-directory inside userData where conversation files live. */
1314
const CHAT_DIR = "chat-history";
@@ -273,9 +274,9 @@ export async function saveConversation(conversation: Conversation): Promise<{ ok
273274
return { ok: true };
274275
} catch (err) {
275276
await fs.unlink(tempPath).catch(() => undefined);
276-
const message = err instanceof Error ? err.message : String(err);
277-
logError("Failed to write conversation file", { path: filePath, error: message });
278-
return { ok: false, error: message };
277+
const diagnostic = redactErrorMessage(err);
278+
logError("Failed to write conversation file", { path: path.basename(filePath), error: diagnostic });
279+
return { ok: false, error: "Failed to save conversation." };
279280
}
280281
}
281282

electron/services/mediaService.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ export interface MediaImportResult {
198198

199199
/** Decodes raw bytes to a data URL. Content type is sniffed from the
200200
* leading bytes (PNG / JPEG / WebP / GIF). */
201-
function sniffContentType(buffer: Buffer): string {
201+
function sniffContentType(buffer: Buffer): string | null {
202202
if (buffer.length >= 8 && buffer[0] === 0x89 && buffer[1] === 0x50 && buffer[2] === 0x4e && buffer[3] === 0x47) {
203203
return "image/png";
204204
}
@@ -215,7 +215,7 @@ function sniffContentType(buffer: Buffer): string {
215215
) {
216216
return "image/webp";
217217
}
218-
return "application/octet-stream";
218+
return null;
219219
}
220220

221221
/** Reads a file from a path the renderer provides. The path must be inside
@@ -237,10 +237,10 @@ export async function importMediaFromPath(input: { filePath: string }): Promise<
237237
return { ok: false, error: "File not found." };
238238
}
239239

240-
const allowedDirs = await canonicalizeBaseDirs(importSafeBaseDirs());
240+
const allowedDirs = await canonicalizeBaseDirs([picturesBaseDir(), thumbsDir()]);
241241
const isAllowed = allowedDirs.some((dir) => isWithin(dir, resolved));
242242
if (!isAllowed) {
243-
return { ok: false, error: "File must be inside Downloads, Documents, Desktop, or Pictures/Venice Forge." };
243+
return { ok: false, error: "File must be inside Pictures/Venice Forge." };
244244
}
245245

246246
const stat = await fs.stat(resolved);
@@ -253,6 +253,9 @@ export async function importMediaFromPath(input: { filePath: string }): Promise<
253253

254254
const buffer = await fs.readFile(resolved);
255255
const contentType = sniffContentType(buffer);
256+
if (!contentType) {
257+
return { ok: false, error: "Unsupported media type." };
258+
}
256259
const dataUrl = `data:${contentType};base64,${buffer.toString("base64")}`;
257260

258261
return {

electron/services/rpSingleFileStore.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import crypto from "crypto";
88
import fs from "fs/promises";
99
import path from "path";
1010
import { logError, logInfo } from "./logger";
11+
import { redactErrorMessage } from "../../src/shared/redaction";
1112

1213
const TMP_SUFFIX = ".tmp";
1314
const VALID_ID_RE = /^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,127}$/;
@@ -110,7 +111,9 @@ export function createSingleFileStore<T>(
110111
if (err && typeof err === "object" && "code" in err && (err as NodeJS.ErrnoException).code === "ENOENT") {
111112
return { ok: true };
112113
}
113-
return { ok: false, error: err instanceof Error ? err.message : String(err) };
114+
const diagnostic = redactErrorMessage(err);
115+
logError("Failed to remove RP file", { id, error: diagnostic });
116+
return { ok: false, error: "Failed to delete item." };
114117
}
115118
}
116119

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@
7676
"dist:win": "npm run verify:icon && npm run build && electron-builder --config electron-builder.config.cjs --win --publish never && npm run checksum:release",
7777
"dist:portable": "npm run verify:icon && npm run build && electron-builder --config electron-builder.config.cjs --win portable --publish never && npm run checksum:release",
7878
"dist:mac": "npm run verify:icon && npm run build && electron-builder --config electron-builder.config.cjs --mac --publish never && npm run checksum:release",
79-
"dist:linux": "npm run verify:icon && npm run build && electron-builder --config electron-builder.config.cjs --linux --publish never",
79+
"dist:linux": "npm run verify:icon && npm run build && electron-builder --config electron-builder.config.cjs --linux --publish never && npm run checksum:release",
8080
"dist:mac:arm64": "npm run verify:icon && npm run build && electron-builder --config electron-builder.config.cjs --mac --arm64 --publish never && npm run checksum:release",
8181
"dist:mac:x64": "npm run verify:icon && npm run build && electron-builder --config electron-builder.config.cjs --mac --x64 --publish never && npm run checksum:release",
8282
"ci": "npm run lint:eslint && npm run typecheck && npm test && npm audit --omit=dev --audit-level=moderate && npm run verify:safety-guard && npm run verify:markdown-links && npm run verify:contracts && npm run build && npm run verify:dist",

scripts/clean-repo-zip.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,8 @@ RSYNC_EXCLUDES=(
240240
"--exclude=docs/AGENTS/"
241241
"--exclude=docs/HQE_AUDIT_REPORT.md"
242242
"--exclude=todo.md"
243+
"--exclude=kimi-export-session_*.md"
244+
"--exclude=*_ledger.py"
243245
"--exclude=scripts/dev-tools/venice-styles.json"
244246
"--include=.config/*.example.yaml"
245247
"--include=.config/*.example.yml"

scripts/verify-archive-clean.cjs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ const BAD_PATTERNS = [
6161
/(^|\/)\.config\/.*\.local\.(yaml|yml)$/,
6262
// Agent scratch space (gitignored, never archive)
6363
/(^|\/)docs\/AGENTS\//,
64+
/(^|\/)kimi-export-session_.*\.md$/,
65+
/(^|\/).*_ledger\.py$/,
6466
];
6567

6668
const SKIP_DIRS = new Set([".git", "node_modules"]);

0 commit comments

Comments
 (0)