Skip to content

fix(live): keep frame forensics metadata-only - #180

Closed
luvs01 wants to merge 1 commit into
devfrom
codex/propose-fix-for-live-frame-logging-vulnerability
Closed

luvs01 wants to merge 1 commit into
devfrom
codex/propose-fix-for-live-frame-logging-vulnerability

Conversation

@luvs01

@luvs01 luvs01 commented Aug 8, 2026 •

Copy link
Copy Markdown
Owner

Motivation

  • The env-gated live sideband forensic logger could include short decoded payload excerpts around U+FFFD, which for short frames or decoded-binary cases leaked user content contrary to the metadata-only intent.
  • The log file was created with default permissions, making diagnostic files potentially readable by others on typical umasks.

Description

  • Stop extracting and writing any context text from frames and record only metadata fields: ts, dir, kind, bytes, and a boolean fffd flag when U+FFFD is present in decoded text, implemented in logLiveSidebandFrame in src/server/live.ts.
  • Avoid decoding-derived excerpts for binary or view frames; detect U+FFFD presence via String.prototype.includes over the decoder result and do not persist surrounding text.
  • Create/append the forensic JSONL file with owner-only permissions (0o600) by passing { mode: 0o600 } to appendFileSync so new files are private on POSIX systems.
  • Update the regression in tests/server-live.test.ts to assert that no context property or payload text is present in the log and to check POSIX file mode is 0600 when applicable.

Testing

  • Ran bun run typecheck, which succeeded (no type errors).
  • Ran the focused test bun run test -- tests/server-live.test.ts --test-name-pattern "sideband frame log records metadata without payload content", which passed and verifies metadata-only logging and file permissions.
  • Ran bun run privacy:scan, which passed.
  • A full bun run test was started under the pinned Bun runtime; it exercised many suites but an unrelated existing test (tests/server-auth.test.ts) failed (expected 401 vs received 403) during the full run and that unrelated failure was observed while the overall long suite was running.

Codex Task

Summary by CodeRabbit

  • Bug Fixes
    • Sideband frame diagnostics now record metadata only, including frame direction, type, size, and replacement-character detection.
    • Diagnostic logs no longer include payload data or surrounding text excerpts.
    • Diagnostic log files are now created with owner-only access permissions.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@github-actions github-actions Bot changed the title fix(live): keep frame forensics metadata-only [WRONG BRANCH] fix(live): keep frame forensics metadata-only Aug 8, 2026
@github-actions
github-actions Bot marked this pull request as draft August 8, 2026 15:59
@coderabbitai

coderabbitai Bot commented Aug 8, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Sideband frame diagnostics now record metadata without payload excerpts. They track U+FFFD presence across text and binary payloads. Diagnostic files use owner-only permissions, with tests covering log content and non-Windows permissions.

Changes

Sideband diagnostic logging

Layer / File(s) Summary
Metadata-only frame logging
src/server/live.ts
Sideband logs retain frame direction, kind, byte length, and a boolean U+FFFD indicator for text, ArrayBuffer, and typed-array payloads. Payload excerpts and context data are removed. Log files use mode 0o600.
Diagnostic logging validation
tests/server-live.test.ts
Tests verify that frame logs contain no payload or context content and that non-Windows log files have 0600 permissions.

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: wibias, lidge-jun, ingwannu

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: live frame forensics now stores metadata only. It matches the metadata-only logging objective and is specific enough for project history.
✨ Finishing Touches 💡 2
⚔️ Resolve merge conflicts 💡
  • Resolve merge conflict in branch codex/propose-fix-for-live-frame-logging-vulnerability
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/propose-fix-for-live-frame-logging-vulnerability

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with 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.

Inline comments:
In `@src/server/live.ts`:
- 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.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 18ff4741-3c9f-4f44-bbf0-da4c85da76fc

📥 Commits

Reviewing files that changed from the base of the PR and between 8a9c0ef and 59d9f74.

📒 Files selected for processing (2)
  • src/server/live.ts
  • tests/server-live.test.ts

Comment thread src/server/live.ts
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.

@luvs01 luvs01 closed this Aug 19, 2026
@luvs01 luvs01 reopened this Aug 19, 2026
@luvs01 luvs01 reopened this Aug 19, 2026
@github-actions

Copy link
Copy Markdown

✅ Deterministic PR hygiene checks passed.

@github-actions

github-actions Bot commented Aug 19, 2026 •

Copy link
Copy Markdown

✅ READY

  • this PR is ready for review.

Hygiene

✅ Deterministic PR hygiene checks passed.

luvs01 pushed a commit that referenced this pull request Aug 28, 2026
Two independent reviewers found the same defect: the fix was half-inert. apiError
gained a status parameter and apiJson gained transportError, and no production
caller passed or read either, so the 404 to 4 and 409 to 5 mapping never ran and
the retained transport cause was never printed. The behavior existed only in this
phase's own tests while the commit message claimed it shipped. Status is now
threaded through all 19 apiError call sites and the cause through the 14
status === 0 guards; two new tests assert the call sites rather than the helpers,
so it cannot go inert again.

tray had the identical lidge-jun#2697 defect: windowsTrayCommand reports failure through
process.exitCode and returns void, so ocx tray install printed an error and exited
0. The recurrence guard could not see it because the pattern was anchored on
'await handle\w+(', scoping it to a naming convention rather than to the defect
class. Broadened to 'await [\w.]+(', which surfaced four more candidates; each was
verified in its handler before being allowlisted with its own reason.

Also corrects the login allowlist reason (it throws rather than exits 1), passes
the env seam through to configuredAdminToken so doctor's check no longer reads real
machine state for half its comparison, and extends assertNotAdminToken with the
equality arm that catches an operator-set admin token without the ocx_admin_ prefix.

The #180 matrix test asserting a 404 exits 1 now expects 4. That issue is a feature
request, not an exit-code contract; the test described then-current behavior, and
the change is the one 010.3 specified and the PR disclosed.
@luvs01 luvs01 changed the title [WRONG BRANCH] fix(live): keep frame forensics metadata-only fix(live): keep frame forensics metadata-only Sep 3, 2026
@luvs01
luvs01 changed the base branch from main to dev September 3, 2026 06:25
@github-actions github-actions Bot added the bug Something isn't working label Sep 3, 2026
@github-actions
github-actions Bot marked this pull request as ready for review September 3, 2026 06:35
@luvs01

luvs01 commented Sep 20, 2026

Copy link
Copy Markdown
Owner Author

Ported upstream; closing.

@luvs01 luvs01 closed this Sep 20, 2026
devin-ai-integration Bot added a commit that referenced this pull request Sep 26, 2026
cli-account.test.ts sits exactly at its file-size ratchet cap (2313); the
new test pushed it to 2336 and failed 'file-size ratchet: repository'.
cli-account-alias-target.test.ts is the sibling kept out of the #180 matrix
file for this reason, so the case moves there byte-for-byte semantics,
ported to that file's harness.

Co-Authored-By: Devin AI <devin-ai-integration[bot]@users.noreply.github.com>
@github-actions
github-actions Bot deleted the codex/propose-fix-for-live-frame-logging-vulnerability branch October 4, 2026 12:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

aardvark bug Something isn't working codex

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant