Skip to content

feat(changes): checkpoint API + git changes panel with zero external deps#682

Merged
esengine merged 5 commits into
esengine:mainfrom
ForeverYoungPp:feat/618-changes-review-panel-1
May 12, 2026
Merged

feat(changes): checkpoint API + git changes panel with zero external deps#682
esengine merged 5 commits into
esengine:mainfrom
ForeverYoungPp:feat/618-changes-review-panel-1

Conversation

@ForeverYoungPp

Copy link
Copy Markdown

What
新增 Checkpoint 完整 CRUD API(创建/列表/diff/还原/删除)及 Dashboard 界面,同时移植了 Git Changes 面板,diff 解析改用手写解析器。零新外部依赖。

Why
缺乏可视化操作,既然是有操作界面就把缺的完善。

How to verify
npm run build — 编译通过
npm run test — 有4个好像是旧失败,我就跳过了
启动 Dashboard,分别切换 Git changes / Checkpoint / Previous session 三个 tab 查看

Comment thread src/server/api/file-read.ts Fixed
@esengine

Copy link
Copy Markdown
Owner

Thanks for the PR — build is green, but CodeQL is failing on a real one: js/file-system-race (high severity) at src/server/api/file-read.ts:85. Worth fixing before merge.

The pattern flagged is:

if (!existsSync(fullPath)) { ... }   // check
st = statSync(fullPath);              // race window — file can change
...
readFileSync(fullPath, "utf-8");      // race window again

Three separate filesystem touches against the same path. Between any two of them the path can be swapped (symlink flip, rename), so the isFile() / size guards you ran on statSync don't necessarily describe the bytes readFileSync ends up returning. CodeQL refuses to assume otherwise.

The fix is to open the file once and do all the checks against the same file descriptor:

import { openSync, fstatSync, readSync, closeSync } from "node:fs";

let fd: number;
try {
  fd = openSync(fullPath, "r");
} catch (err) {
  const code = (err as NodeJS.ErrnoException).code;
  if (code === "ENOENT") {
    return { status: 404, body: { error: `file not found: ${filePath}` } };
  }
  return { status: 500, body: { error: "cannot open file" } };
}
try {
  const st = fstatSync(fd);
  if (!st.isFile()) return { status: 400, body: { error: "not a file" } };
  if (st.size > MAX_FILE_SIZE) {
    return {
      status: 413,
      body: { error: `file too large (${st.size} bytes, max ${MAX_FILE_SIZE})` },
    };
  }
  const buf = Buffer.alloc(st.size);
  readSync(fd, buf, 0, st.size, 0);
  return { status: 200, body: { content: buf.toString("utf-8"), path: filePath, size: st.size } };
} finally {
  closeSync(fd);
}

fstatSync + readSync both operate on the fd, not the path, so the inode is pinned for the duration. Drop the leading existsSyncopenSync's ENOENT covers that case.

One more thing while you're in this file: join(cwd, filePath) does not block path traversal. filePath = "../../etc/passwd" resolves outside cwd. Normalize with path.resolve(cwd, filePath) and reject if the result doesn't start with cwd + path.sep. The dashboard binds localhost-only by default, but the API shouldn't trust the path either way.

Push the fix and CodeQL should clear.

@esengine esengine merged commit 5818481 into esengine:main May 12, 2026
3 checks passed
@ForeverYoungPp

Copy link
Copy Markdown
Author

感谢你细致的评审

esengine added a commit that referenced this pull request May 12, 2026
…il, CardStream fix (#705)

npm-only release. The Tauri desktop source is in the repo and the CLI
subcommand works, but installer bundles for macOS / Windows / Linux
don't ship this round (separate release once signing's settled).

Highlights:
- Tauri desktop client with multi-tab concurrent runtimes (#689)
  plus a near-full polish pass: wallet balance, version chip, active-
  plan rail, abortable pause-gates, edit-gate pill, en + zh-CN i18n,
  shared pause-policy module dedup'd with the CLI TUI (#701)
- checkpoint API + git-changes panel in the embedded dashboard (#682)
- outside-sandbox file access approval modal (#696)
- MCP loading pill + readiness gate on tool dispatch (#687)
- escalate-after flag for flash → pro threshold (#699)

Fixes:
- CardStream Maximum-update-depth crash, quantize window so boundary
  cards stop oscillating (#700, #702)
- `reasonix code` bridges config key to env + lazy subagent client so
  fresh installs can reach the setup wizard (#703)
- pinned-mode scroll shrinks coalesced (#666), generic CSI key decode
  (#692), shell-confirm preview clamp (#691), frontmatter BOM/folded
  lines (#690), MCP error classification (#688), and more
ChasLui pushed a commit to ChasLui/DeepSeek-Reasonix that referenced this pull request May 23, 2026
…deps (esengine#682)

* feat: checkpoint API + git changes panel with zero external deps

* fix(changes): Cross-site scripting vulnerability as the output of this final HTML sanitizer step may contain double quotes when it reaches this attribute definition.

* fix(changes): The file may have changed since it was checked

* fix(comment): shorten block comment to comply with policy

* fix(file-read): TOCTOU race + path traversal guard
ChasLui pushed a commit to ChasLui/DeepSeek-Reasonix that referenced this pull request May 23, 2026
…il, CardStream fix (esengine#705)

npm-only release. The Tauri desktop source is in the repo and the CLI
subcommand works, but installer bundles for macOS / Windows / Linux
don't ship this round (separate release once signing's settled).

Highlights:
- Tauri desktop client with multi-tab concurrent runtimes (esengine#689)
  plus a near-full polish pass: wallet balance, version chip, active-
  plan rail, abortable pause-gates, edit-gate pill, en + zh-CN i18n,
  shared pause-policy module dedup'd with the CLI TUI (esengine#701)
- checkpoint API + git-changes panel in the embedded dashboard (esengine#682)
- outside-sandbox file access approval modal (esengine#696)
- MCP loading pill + readiness gate on tool dispatch (esengine#687)
- escalate-after flag for flash → pro threshold (esengine#699)

Fixes:
- CardStream Maximum-update-depth crash, quantize window so boundary
  cards stop oscillating (esengine#700, esengine#702)
- `reasonix code` bridges config key to env + lazy subagent client so
  fresh installs can reach the setup wizard (esengine#703)
- pinned-mode scroll shrinks coalesced (esengine#666), generic CSI key decode
  (esengine#692), shell-confirm preview clamp (esengine#691), frontmatter BOM/folded
  lines (esengine#690), MCP error classification (esengine#688), and more
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants