fix(sync): harden sync CLI, IPC, and UI paths from CodeRabbit review

- reject option-like tokens as flag values (--snapshot --force wrote a
  file named --force); --flag=-value still works
- PowerShell remote quoting uses single-quoted literals so $() in a
  quoted path cannot expand
- sync-hosts.json written via temp file + rename; a crash mid-write
  truncated it and the reader's corrupt-fallback dropped every host
- cancelled sync child escalates SIGTERM -> SIGKILL after 5s grace
- NDJSON progress events validated field-by-field before casting
- snapshot filenames include milliseconds to avoid same-second overwrite
- syncAutoScheduler.stop() wired into will-quit cleanup
- sync --ui exclusivity also rejects --make-temp/--remove-temp/--json
- document --sync-window in app help; group --make-temp/--remove-temp
  under modes in sync usage
This commit is contained in:
2026-07-12 02:10:04 -07:00
parent 25cca8ce24
commit c9f85473bb
19 changed files with 257 additions and 27 deletions
+12 -6
View File
@@ -100,15 +100,21 @@ export function detectRemoteShellFlavor(
}
/**
* Quote one argument for the detected remote shell. Windows shells have no
* safe single-quote escaping (cmd treats ' literally; PowerShell and cmd
* disagree on embedded double quotes), so quote-containing values are
* rejected instead of escaped — sync only ever quotes paths it composed.
* Quote one argument for the detected remote shell. PowerShell expands $(...)
* and $var inside double quotes, so it gets a single-quoted literal ('' escapes
* a quote). cmd.exe has no single-quote form and treats ' literally, so it keeps
* double quotes and rejects values carrying a double quote of their own.
*/
export function quoteForRemoteShell(flavor: RemoteShellFlavor, value: string): string {
if (flavor === 'posix') return shellQuote(value);
if (value.includes('"') || /[\r\n]/.test(value)) {
throw new Error(`Refusing to quote a value with quotes or newlines for a Windows shell: ${value}`);
if (/[\r\n]/.test(value)) {
throw new Error(`Refusing to quote a value with newlines for a Windows shell: ${value}`);
}
if (flavor === 'windows-powershell') {
return `'${value.replaceAll("'", "''")}'`;
}
if (value.includes('"')) {
throw new Error(`Refusing to quote a value with quotes for a Windows shell: ${value}`);
}
return `"${value}"`;
}