Skip to content

refactor(main): extract pure path/id/mime helpers into paths.ts with unit tests#55

Merged
thisiscsim merged 1 commit into
mainfrom
refactor/main-modules
Jul 19, 2026
Merged

refactor(main): extract pure path/id/mime helpers into paths.ts with unit tests#55
thisiscsim merged 1 commit into
mainfrom
refactor/main-modules

Conversation

@thisiscsim

Copy link
Copy Markdown
Owner

Summary

Audit roadmap Phase 6 (main-process decomposition) — the first, safe slice. The audit proposed splitting the 1,800-line index.ts into ~12 modules; this lands the highest-value, zero-risk piece and makes the security-critical logic testable.

  • New app/src/main/paths.ts (no electron imports) holds the pure helpers: safePath, assertSlug, isSafeExternalUrl, assetKindFor + the extension sets, slugify, mimeFor, and writeFileAtomic. index.ts imports them; the root-keyed wrappers safeProjectPath/safeStylePath stay in index.ts because they close over PROJECTS_DIR/STYLES_DIR.
  • New paths.test.ts (14 assertions across 10 cases): safePath traversal + sibling-prefix (<root>-evil) + absolute-segment containment, the assertSlug allow/deny set, the https-only external-URL guard, and assetKindFor/mimeFor/slugify. safePath and assertSlug had no coverage before despite being the path-traversal boundary.

Deliberately deferred (called out for a follow-up): the domain split (projects / media / watcher / albums / styles / voices / scripts / ipc) closes over startup-ordered module state — envLocked must be captured after loadLocalEnv() but before applyAgentEnv, and APP_HOME/PROJECTS_DIR resolve from readSettings().homeDir at a precise point. Moving those carelessly would change boot behavior, so they deserve their own verifiable step rather than being rushed in here.

Pure extraction — no behavior change. Main-process file moved, so restart npm run dev.

Test plan

  • paths.test.ts green; 114 tests total
  • typecheck / lint / format / build green
  • Diff is move-only for the extracted helpers (no logic edits)

Made with Cursor

…unit tests

First, safe slice of the main-process decomposition: the pure, security-
sensitive helpers move to app/src/main/paths.ts (no electron imports), so the
containment logic is unit-testable without booting Electron —
safePath, assertSlug, isSafeExternalUrl, assetKindFor, slugify, mimeFor,
writeFileAtomic, and the extension sets. index.ts imports them; the
slug/root-keyed wrappers (safeProjectPath/safeStylePath) stay since they
close over PROJECTS_DIR/STYLES_DIR.

Adds paths.test.ts covering the traversal / sibling-prefix / absolute-
segment cases for safePath, the assertSlug allow/deny set, the https-only
external-URL guard, and mime/kind/slugify.

The remaining domain split (projects/media/watcher/albums/styles/voices/
scripts/ipc) is deliberately deferred: those close over startup-ordered
module state (envLocked capture vs loadLocalEnv vs APP_HOME resolution)
where a careless move would change boot behavior — worth doing as its own
verifiable step. No behavior change here (typecheck + build + 114 tests green).

Co-authored-by: Cursor <cursoragent@cursor.com>
@thisiscsim
thisiscsim merged commit b8b4271 into main Jul 19, 2026
1 check passed
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.

1 participant