Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 8 additions & 19 deletions src/server/live.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,39 +80,29 @@ export const LIVE_CLIENT_PROTOCOL_HEADERS = [
*
* When `OCX_LIVE_FRAME_LOG` is set to a file path, every relayed sideband frame appends one
* JSONL record: direction, frame kind, byte length, and whether the payload contains U+FFFD.
* Privacy: full frame payloads are never written — only when U+FFFD is present, a short
* excerpt around the first replacement character is included so the corruption point can be
* attributed (upstream vs relay vs client). Disabled entirely when the env var is unset.
* Privacy: frame payloads are never written. The log is created with owner-only permissions and
* is disabled entirely when the env var is unset.
*/
export const LIVE_FRAME_LOG_ENV = "OCX_LIVE_FRAME_LOG";
const LIVE_FRAME_LOG_CONTEXT_CHARS = 24;

function fffdContext(text: string): string | undefined {
const idx = text.indexOf("\uFFFD");
if (idx < 0) return undefined;
const start = Math.max(0, idx - LIVE_FRAME_LOG_CONTEXT_CHARS);
const end = Math.min(text.length, idx + LIVE_FRAME_LOG_CONTEXT_CHARS);
return text.slice(start, end);
}

export function logLiveSidebandFrame(dir: "c2u" | "u2c", data: unknown): void {
const logPath = process.env[LIVE_FRAME_LOG_ENV];
if (!logPath) return;
try {
let kind: "text" | "binary" = "binary";
let bytes = 0;
let context: string | undefined;
let fffd = false;
if (typeof data === "string") {
kind = "text";
bytes = Buffer.byteLength(data);
context = fffdContext(data);
fffd = data.includes("\uFFFD");
} else if (data instanceof ArrayBuffer) {
bytes = data.byteLength;
context = fffdContext(new TextDecoder().decode(new Uint8Array(data)));
fffd = new TextDecoder().decode(new Uint8Array(data)).includes("\uFFFD");
} else if (ArrayBuffer.isView(data)) {
const view = new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
bytes = data.byteLength;
context = fffdContext(new TextDecoder().decode(view));
fffd = new TextDecoder().decode(view).includes("\uFFFD");
} else {
return;
}
Expand All @@ -121,10 +111,9 @@ export function logLiveSidebandFrame(dir: "c2u" | "u2c", data: unknown): void {
dir,
kind,
bytes,
fffd: context !== undefined,
...(context !== undefined ? { context } : {}),
fffd,
};
appendFileSync(logPath, `${JSON.stringify(record)}\n`);
appendFileSync(logPath, `${JSON.stringify(record)}\n`, { mode: 0o600 });

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- candidate files ---'
git ls-files 'src/server/live.ts' 'tests/server-live.test.ts' 'package.json' 'bun.lock' 'bun.lockb' 'tsconfig.json'

printf '%s\n' '--- source outline ---'
ast-grep outline src/server/live.ts || true

printf '%s\n' '--- source context ---'
sed -n '1,180p' src/server/live.ts

printf '%s\n' '--- test context ---'
sed -n '810,875p' tests/server-live.test.ts

printf '%s\n' '--- filesystem permission references ---'
rg -n -S 'appendFileSync|fchmodSync|chmodSync|frameLogPath|logPath|forensic|frame log' src tests package.json bun.lock bun.lockb 2>/dev/null || true

printf '%s\n' '--- runtime/config context ---'
for f in package.json bun.lock bun.lockb tsconfig.json; do
  if [ -f "$f" ]; then
    echo "### $f"
    sed -n '1,180p' "$f"
  fi
done

Repository: luvs01/opencodex

Length of output: 50372


🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- enclosing frame-log test ---'
rg -n -B 45 -A 12 'frameLogPath|OCX_LIVE_FRAME_LOG|frame-log' tests/server-live.test.ts

printf '%s\n' '--- package scripts and runtime declarations ---'
node - <<'JS'
const fs = require("fs");
const pkg = JSON.parse(fs.readFileSync("package.json", "utf8"));
console.log(JSON.stringify({
  engines: pkg.engines,
  type: pkg.type,
  scripts: pkg.scripts,
  dependencies: pkg.dependencies,
  devDependencies: pkg.devDependencies,
}, null, 2));
JS

printf '%s\n' '--- focused permission patterns ---'
rg -n -S -C 3 'chmodSync\(path, 0o600\)|appendFileSync\(path|openSync\(.*0o600|fchmodSync' src/usage src/server tests/server-live.test.ts

printf '%s\n' '--- standalone existing-file mode probe ---'
node - <<'JS'
"use strict";
const {
  appendFileSync,
  chmodSync,
  mkdtempSync,
  readFileSync,
  rmSync,
  statSync,
} = require("node:fs");
const { join } = require("node:path");
const { tmpdir } = require("node:os");

const dir = mkdtempSync(join(tmpdir(), "ocx-mode-probe-"));
const path = join(dir, "frame.jsonl");
try {
  appendFileSync(path, "seed\n", { mode: 0o644 });
  chmodSync(path, 0o644);
  const before = statSync(path).mode & 0o777;
  appendFileSync(path, "record\n", { mode: 0o600 });
  const after = statSync(path).mode & 0o777;
  console.log(JSON.stringify({ before: before.toString(8), after: after.toString(8), content: readFileSync(path, "utf8") }));
} finally {
  rmSync(dir, { recursive: true, force: true });
}
JS

Repository: luvs01/opencodex

Length of output: 10915


🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- Bun availability ---'
if command -v bun >/dev/null 2>&1; then
  bun --version
  printf '%s\n' '--- Bun node:fs descriptor probe ---'
  bun - <<'JS'
import { chmodSync, closeSync, fchmodSync, mkdtempSync, openSync, readFileSync, rmSync, statSync, writeSync } from "node:fs";
import { join } from "node:path";
import { tmpdir } from "node:os";

const dir = mkdtempSync(join(tmpdir(), "ocx-bun-mode-probe-"));
const path = join(dir, "frame.jsonl");
try {
  writeSync(openSync(path, "w", 0o644), "seed\n");
  chmodSync(path, 0o644);
  const before = statSync(path).mode & 0o777;
  const fd = openSync(path, "a", 0o600);
  fchmodSync(fd, 0o600);
  writeSync(fd, "record\n");
  closeSync(fd);
  const after = statSync(path).mode & 0o777;
  console.log(JSON.stringify({ before: before.toString(8), after: after.toString(8), content: readFileSync(path, "utf8") }));
} finally {
  rmSync(dir, { recursive: true, force: true });
}
JS
else
  echo 'bun unavailable'
fi

printf '%s\n' '--- test imports and TEST_DIR lifecycle ---'
sed -n '1,90p' tests/server-live.test.ts
rg -n -B 8 -A 12 'TEST_DIR|rmSync\(TEST_DIR|mkdirSync\(TEST_DIR|mkdtempSync' tests/server-live.test.ts

Repository: luvs01/opencodex

Length of output: 6885


🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- Bun availability ---'
if command -v bun >/dev/null 2>&1; then
  bun --version
  printf '%s\n' '--- Bun node:fs descriptor probe ---'
  bun - <<'JS'
import { chmodSync, closeSync, fchmodSync, mkdtempSync, openSync, readFileSync, rmSync, statSync, writeSync } from "node:fs";
import { join } from "node:path";
import { tmpdir } from "node:os";

const dir = mkdtempSync(join(tmpdir(), "ocx-bun-mode-probe-"));
const path = join(dir, "frame.jsonl");
try {
  const seedFd = openSync(path, "w", 0o644);
  writeSync(seedFd, "seed\n");
  closeSync(seedFd);
  chmodSync(path, 0o644);
  const before = statSync(path).mode & 0o777;
  const fd = openSync(path, "a", 0o600);
  fchmodSync(fd, 0o600);
  writeSync(fd, "record\n");
  closeSync(fd);
  const after = statSync(path).mode & 0o777;
  console.log(JSON.stringify({ before: before.toString(8), after: after.toString(8), content: readFileSync(path, "utf8") }));
} finally {
  rmSync(dir, { recursive: true, force: true });
}
JS
else
  echo 'bun unavailable'
fi

printf '%s\n' '--- test imports and TEST_DIR lifecycle ---'
sed -n '1,90p' tests/server-live.test.ts
rg -n -B 8 -A 12 'TEST_DIR|rmSync\(TEST_DIR|mkdirSync\(TEST_DIR|mkdtempSync' tests/server-live.test.ts

Repository: luvs01/opencodex

Length of output: 6885


Harden reused frame log files before appending.

{ mode: 0o600 } affects only file creation. If OCX_LIVE_FRAME_LOG points to an existing 0o644 file, logLiveSidebandFrame keeps its permissive mode. On POSIX, open the file, call fchmodSync(fd, 0o600), append the record, and close the descriptor.

In tests/server-live.test.ts, retain the creation-path assertion and add a reuse-path case that pre-creates frameLogPath with 0o644, invokes the logger, and asserts 0o600.

📍 Affects 2 files
  • src/server/live.ts#L116-L116 (this comment)
  • tests/server-live.test.ts#L850-L850
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/server/live.ts` at line 116, Update logLiveSidebandFrame in
src/server/live.ts to open the frame log descriptor, enforce mode 0o600 with
fchmodSync, append the record through that descriptor, and close it reliably. In
tests/server-live.test.ts:850, retain the creation-path permission assertion and
add a reuse-path case that pre-creates frameLogPath with mode 0o644, invokes the
logger, and verifies it becomes 0o600.

} catch {
// Frame forensics must never break the relay.
}
Expand Down
10 changes: 6 additions & 4 deletions tests/server-live.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* so the proxy must relay it to an OpenAI upstream instead of the /v1/* JSON-404 guard.
*/
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
import { existsSync, mkdirSync, readFileSync, rmSync } from "node:fs";
import { existsSync, mkdirSync, readFileSync, rmSync, statSync } from "node:fs";
import { join } from "node:path";
import { saveCodexAccountCredential } from "../src/codex/account-store";
import { clearAccountNeedsReauth, clearAccountQuota } from "../src/codex/auth-api";
Expand Down Expand Up @@ -760,7 +760,7 @@ test("sideband relay preserves multibyte UTF-8 frames byte-identically in both d
// The env-gated frame forensic log (OCX_LIVE_FRAME_LOG) records per-frame metadata and
// U+FFFD presence without writing full payloads — the attribution tool for multibyte
// transcript corruption reports.
test("sideband frame log records direction, kind, and U+FFFD context without full payloads", async () => {
test("sideband frame log records metadata without payload content", async () => {
const frameLogPath = join(TEST_DIR, "frames.jsonl");
process.env.OCX_LIVE_FRAME_LOG = frameLogPath;
const FFFD_TEXT = "가볍게 ��기핼봐요";
Expand Down Expand Up @@ -839,13 +839,15 @@ test("sideband frame log records direction, kind, and U+FFFD context without ful
expect(u2cFffd).toBeDefined();
expect(u2cFffd.kind).toBe("text");
expect(u2cFffd.bytes).toBeGreaterThan(0);
expect(u2cFffd.context).toContain("�");
expect(u2cFffd).not.toHaveProperty("context");
expect(c2uClean).toBeDefined();
expect(c2uClean.fffd).toBe(false);
// Full payloads must never be logged — only short FFFD context excerpts.
// No payload content is logged, including frames containing U+FFFD.
for (const line of lines) {
expect(JSON.stringify(line)).not.toContain("clean-frame");
expect(JSON.stringify(line)).not.toContain(FFFD_TEXT);
}
if (process.platform !== "win32") expect(statSync(frameLogPath).mode & 0o777).toBe(0o600);

client.close();
} finally {
Expand Down
Loading