Skip to content

Commit 181e2c4

Browse files
authored
fix(macos): parse runtime state with bundled Node.js (#27)
Remove the system Python and shell eval dependency from runtime-state restoration. Parse saved values as data with the validated bundled Node runtime and add command-injection regression coverage.
1 parent 170b844 commit 181e2c4

3 files changed

Lines changed: 52 additions & 11 deletions

File tree

macos/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
- 修正内置主题引用了未随仓库发布的背景文件,恢复使用 bundled abstract demo 素材
88
- 更新主题配置往返测试:安装只备份外观键,不再错误断言强制切换深色模式
99
- 恢复原本没有 `[desktop]` 配置段的用户设置时,不再额外写入空段
10+
- 热切换读取运行状态时复用 Codex 内置 Node.js,不再依赖系统 `python3` 或执行 `eval`
1011

1112
---
1213

macos/scripts/common-macos.sh

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,22 @@ state_field() {
276276
' "$STATE_PATH" "$key"
277277
}
278278

279+
restore_runtime_context_from_state() {
280+
[ -f "$STATE_PATH" ] || return 0
281+
local value=""
282+
283+
value="$(state_field codexBundle 2>/dev/null || true)"
284+
[ -z "$value" ] || CODEX_BUNDLE="$value"
285+
value="$(state_field codexExe 2>/dev/null || true)"
286+
[ -z "$value" ] || CODEX_EXE="$value"
287+
value="$(state_field codexVersion 2>/dev/null || true)"
288+
[ -z "$value" ] || CODEX_VERSION="$value"
289+
value="$(state_field codexTeamId 2>/dev/null || true)"
290+
[ -z "$value" ] || CODEX_TEAM_ID="$value"
291+
292+
export CODEX_BUNDLE CODEX_EXE CODEX_VERSION CODEX_TEAM_ID
293+
}
294+
279295
write_state() {
280296
local port="$1"
281297
local injector_pid="$2"
@@ -441,16 +457,7 @@ ensure_node_runtime() {
441457
: "${CODEX_EXE:=/Applications/Codex.app/Contents/MacOS/ChatGPT}"
442458
: "${CODEX_VERSION:=}"
443459
: "${CODEX_TEAM_ID:=}"
444-
# Soft-fill from state if present
445-
if [ -f "$STATE_PATH" ]; then
446-
eval "$(/usr/bin/python3 -c 'import json,sys
447-
try:
448-
s=json.load(open(sys.argv[1]))
449-
for k,env in [("codexBundle","CODEX_BUNDLE"),("codexExe","CODEX_EXE"),("codexVersion","CODEX_VERSION"),("codexTeamId","CODEX_TEAM_ID")]:
450-
v=s.get(k) or ""
451-
if v: print(f"export {env}={json.dumps(v)}")
452-
except Exception: pass' "$STATE_PATH" 2>/dev/null || true)"
453-
fi
460+
restore_runtime_context_from_state
454461
return 0
455462
fi
456463
done

macos/tests/run-tests.sh

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,44 @@ if /usr/bin/grep -R -n -E '(writeFile|rename|copyFile|rm).*app\.asar' "$ROOT/scr
2222
printf 'A runtime script appears to mutate app.asar.\n' >&2
2323
exit 1
2424
fi
25+
if /usr/bin/grep -n -E '/usr/bin/python3|(^|[[:space:]])eval([[:space:]]|$)' \
26+
"$ROOT/scripts/common-macos.sh" >/dev/null; then
27+
printf 'The shared macOS runtime must parse state with the bundled Node.js, without python3 or eval.\n' >&2
28+
exit 1
29+
fi
2530

2631
"$NODE" "$ROOT/scripts/injector.mjs" --check-payload >/dev/null
2732

2833
TMP="$(/usr/bin/mktemp -d /tmp/codex-dream-skin-tests.XXXXXX)"
2934
trap '/bin/rm -rf "$TMP"' EXIT
35+
36+
RUNTIME_HOME="$TMP/runtime-home"
37+
RUNTIME_STATE_ROOT="$RUNTIME_HOME/Library/Application Support/CodexDreamSkinStudio"
38+
RUNTIME_STATE="$RUNTIME_STATE_ROOT/state.json"
39+
STATE_EVAL_MARKER="$TMP/state-eval-marker"
40+
EXPECTED_BUNDLE="/Applications/Codex \$(touch \"$STATE_EVAL_MARKER\").app"
41+
EXPECTED_EXE="$EXPECTED_BUNDLE/Contents/MacOS/ChatGPT; touch \"$STATE_EVAL_MARKER\""
42+
EXPECTED_VERSION='1.1.2 "nightly"'
43+
EXPECTED_TEAM_ID="TEAM'ID"
44+
/bin/mkdir -p "$RUNTIME_STATE_ROOT"
45+
"$NODE" -e '
46+
const fs = require("node:fs");
47+
const [file, codexBundle, codexExe, codexVersion, codexTeamId] = process.argv.slice(1);
48+
fs.writeFileSync(file, `${JSON.stringify({ codexBundle, codexExe, codexVersion, codexTeamId })}\n`);
49+
' "$RUNTIME_STATE" "$EXPECTED_BUNDLE" "$EXPECTED_EXE" "$EXPECTED_VERSION" "$EXPECTED_TEAM_ID"
50+
/usr/bin/env -u NODE -u NODE_VERSION HOME="$RUNTIME_HOME" /bin/bash -c '
51+
. "$1/scripts/common-macos.sh"
52+
ensure_node_runtime
53+
[ "$CODEX_BUNDLE" = "$2" ]
54+
[ "$CODEX_EXE" = "$3" ]
55+
[ "$CODEX_VERSION" = "$4" ]
56+
[ "$CODEX_TEAM_ID" = "$5" ]
57+
' _ "$ROOT" "$EXPECTED_BUNDLE" "$EXPECTED_EXE" "$EXPECTED_VERSION" "$EXPECTED_TEAM_ID"
58+
[ ! -e "$STATE_EVAL_MARKER" ] || {
59+
printf 'Runtime state values were evaluated as shell code.\n' >&2
60+
exit 1
61+
}
62+
3063
/bin/mkdir -p "$TMP/theme"
3164
/bin/cp "$ROOT/assets/portal-hero.png" "$TMP/theme/background.png"
3265
"$NODE" "$ROOT/scripts/write-theme.mjs" custom --output-dir "$TMP/theme" \
@@ -71,4 +104,4 @@ NO_DESKTOP_BACKUP="$TMP/theme-backup-without-desktop.json"
71104
/usr/bin/env -u HOME /bin/bash -c '. "$1/scripts/common-macos.sh"; [ -n "$HOME" ] && [ "$SKIN_VERSION" = "1.1.2" ]' _ "$ROOT"
72105
"$ROOT/scripts/doctor-macos.sh" >/dev/null
73106

74-
printf 'PASS: syntax, payload, custom-theme, config round-trips, HOME recovery, signature, and doctor checks.\n'
107+
printf 'PASS: syntax, payload, runtime-state safety, custom-theme, config round-trips, HOME recovery, signature, and doctor checks.\n'

0 commit comments

Comments
 (0)