Files
orca/src/main/codex/wsl-codex-session-bridge-script.ts
T
Brennan BensonandMerge Sim 5ff1aa540e fix(codex): re-land WSL direct-home cutover with counsel findings fixed (#16854)
* fix(codex): safely re-land WSL direct homes

* fix(codex): finish WSL direct-home cutover

* fix(codex): coalesce WSL launch hook installs

* perf(codex): avoid duplicate retired WSL session scan

* fix(codex): retain canonical WSL retired-home path

* fix(codex): fail closed before retiring WSL auth

* fix(codex): reopen WSL drain after rollback

* fix(codex): preserve WSL source on unknown panes

* fix(codex): harden repeated WSL runtime drains

* perf(codex): bound pending WSL session scans

* fix(codex): recover invalid WSL session watermarks

* fix(codex): validate retained WSL scan state

* fix(codex): accept durable WSL scan state

* test(codex): cover the drain's inode-identity guard against destination replacement

Removing the four `target_auth -ef temporary_destination_auth` assertions left
all 33 apply-script tests passing, so a regression deleting them would have
shipped silently. Reproduced before writing this.

A hash check cannot catch the case. The pinned hard link keeps the original
inode, so it still hashes correctly after another writer atomically renames a
different file over the destination path; only inode identity sees it. Without
the guard the script exits 0 and retires the source, leaving the user holding
bytes nothing validated. The new case asserts the source survives.

The harness is split by responsibility so no file exceeds its max-lines budget:
fixtures, the coreutils interference shims, the run types, the apply runner, and
the recovery/absent runners. The atomic-rename hook is deliberately separate
from the in-place rewrite shim because different guards catch them.

* fix(codex): keep the split drain harness inside the child-process boundaries

Extracting the harness into non-test modules moved it out of the exemptions the
single test file had: three new files import child_process, and two spawned
without windowsHide.

Adds the three to the import allowlist, and sets windowsHide on the spawns
rather than exempting them - the flag is correct for these calls regardless of
the ratchet, and they are skipped on win32 anyway.

---------

Co-authored-by: Merge Sim <sim@local>
2026-08-31 11:20:22 -07:00

123 lines
4.6 KiB
TypeScript

import { quotePosixShell } from '../../shared/wsl-login-shell-command'
export const WSL_SESSION_BRIDGE_TIMEOUT_MS = 30_000
const WSL_CODEX_SESSION_BRIDGE_BODY = [
'set -u',
'rollback_manifest=${3-}',
'rollback_stage_root=${4-}',
'scan_scope=${5-full}',
'scan_start=${6-}',
'scan_end=${7-}',
'if [ -n "$rollback_manifest" ]; then',
' [ -n "$rollback_stage_root" ] || exit 1',
' mkdir -p -- "$rollback_stage_root" || exit 1',
' : > "$rollback_manifest" || exit 1',
'fi',
'scanned_files=0',
'linked_files=0',
'bridge_failed=0',
'if [ ! -d "$source_sessions_root" ]; then',
` printf '{"scannedFiles":0,"linkedFiles":0}\\n'`,
' exit 0',
'fi',
'file_list=$(mktemp) || exit 1',
'day_list="$file_list.days"',
'trap \'rm -f -- "$file_list" "$day_list"\' EXIT HUP INT TERM',
'case "$scan_scope" in',
` full) find "$source_sessions_root" -type f -name '*.jsonl' -print0 > "$file_list" || exit 1 ;;`,
' recent)',
' case "$scan_start" in ????/??/??) ;; *) exit 1 ;; esac',
' case "$scan_end" in ????/??/??) ;; *) exit 1 ;; esac',
' if [[ "$scan_start" > "$scan_end" ]]; then',
` find "$source_sessions_root" -type f -name '*.jsonl' -print0 > "$file_list" || exit 1`,
' else',
' : > "$file_list" || exit 1',
' find "$source_sessions_root" -mindepth 3 -maxdepth 3 -type d -print0 > "$day_list" || exit 1',
" while IFS= read -r -d '' session_day_root; do",
' session_day=${session_day_root#"$source_sessions_root"/}',
' case "$session_day" in ????/??/??) ;; *) continue ;; esac',
' [[ "$session_day" < "$scan_start" ]] && continue',
' find "$session_day_root" -maxdepth 1 -type f -name \'*.jsonl\' -print0 >> "$file_list" || exit 1',
' done < "$day_list"',
' fi',
' ;;',
' *) exit 1 ;;',
'esac',
"while IFS= read -r -d '' source_file; do",
' scanned_files=$((scanned_files + 1))',
' relative_path=${source_file#"$source_sessions_root"/}',
' target_file="$managed_sessions_root/$relative_path"',
' if [ -e "$target_file" ] || [ -L "$target_file" ]; then',
' continue',
' fi',
' target_dir=${target_file%/*}',
' if ! mkdir -p -- "$target_dir"; then',
' bridge_failed=1',
' continue',
' fi',
' link_source="$source_file"',
' if [ -n "$rollback_manifest" ]; then',
' staged_file="$rollback_stage_root/$relative_path"',
' staged_dir=${staged_file%/*}',
' if ! mkdir -p -- "$staged_dir" || ! ln -- "$source_file" "$staged_file"; then',
' bridge_failed=1',
' continue',
' fi',
' target_stage="$target_file.orca-bridge-$$"',
' if [ -e "$target_stage" ] || [ -L "$target_stage" ]; then',
' bridge_failed=1',
' continue',
' fi',
' if ! ln -- "$staged_file" "$target_stage"; then',
' if ! cp -- "$staged_file" "$target_stage" || ! cmp -s -- "$staged_file" "$target_stage"; then',
' rm -f -- "$target_stage"',
' bridge_failed=1',
' continue',
' fi',
' fi',
' if ! printf \'%s\\0%s\\0\' "$target_stage" "$target_file" >> "$rollback_manifest"; then',
' rm -f -- "$target_stage"',
' bridge_failed=1',
' continue',
' fi',
' link_source="$target_stage"',
' fi',
// Codex resume ignores symlinked JSONL, so create links inside the distro.
' if ln -- "$link_source" "$target_file"; then',
' linked_files=$((linked_files + 1))',
' elif [ ! -e "$target_file" ] && [ ! -L "$target_file" ]; then',
' if [ -n "$rollback_manifest" ]; then',
' bridge_failed=1',
' else',
' target_stage="$target_file.orca-bridge-$$"',
' if [ ! -e "$target_stage" ] && [ ! -L "$target_stage" ] && cp -- "$source_file" "$target_stage" && cmp -s -- "$source_file" "$target_stage" && ln -- "$target_stage" "$target_file"; then',
' linked_files=$((linked_files + 1))',
' else',
' bridge_failed=1',
' fi',
' rm -f -- "$target_stage"',
' fi',
' fi',
'done < "$file_list"',
'[ "$bridge_failed" = 0 ] || exit 1',
`printf '{"scannedFiles":%s,"linkedFiles":%s}\\n' "$scanned_files" "$linked_files"`
].join('\n')
export const WSL_CODEX_SESSION_BRIDGE_SCRIPT = [
'source_sessions_root="$1"',
'managed_sessions_root="$2"',
WSL_CODEX_SESSION_BRIDGE_BODY
].join('\n')
export function buildWslCodexSessionBridgeShellCommand(paths: {
managedSessionsRoot: string
systemSessionsRoot: string
}): string {
return [
`source_sessions_root=${quotePosixShell(paths.systemSessionsRoot)}`,
`managed_sessions_root=${quotePosixShell(paths.managedSessionsRoot)}`,
WSL_CODEX_SESSION_BRIDGE_BODY
].join('\n')
}