From 3fd1db8c2f40c56ca3bea39d1bd49eb6d0af1466 Mon Sep 17 00:00:00 2001 From: john Date: Fri, 24 Jul 2026 10:39:45 +0800 Subject: [PATCH] fix: resolve deep search runtime symlink --- scripts/deep-search-runtime-package.test.mjs | 54 +++++++++++++++++++- scripts/run-deep-search-prod.sh | 3 +- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/scripts/deep-search-runtime-package.test.mjs b/scripts/deep-search-runtime-package.test.mjs index 0c82729..37336b3 100644 --- a/scripts/deep-search-runtime-package.test.mjs +++ b/scripts/deep-search-runtime-package.test.mjs @@ -1,7 +1,19 @@ import test from 'node:test'; import assert from 'node:assert/strict'; -import { readFileSync } from 'node:fs'; +import { + chmodSync, + copyFileSync, + mkdirSync, + mkdtempSync, + realpathSync, + readFileSync, + rmSync, + symlinkSync, + writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; import path from 'node:path'; +import { spawnSync } from 'node:child_process'; import { fileURLToPath } from 'node:url'; const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); @@ -13,6 +25,7 @@ test('Deep Search production runtime is isolated from Portal releases', () => { assert.match(builder, /\.runtime', 'deep-search/); const runner = read('scripts/run-deep-search-prod.sh'); + assert.match(runner, /cd -P/); assert.match(runner, /shared\/\.env/); assert.match(runner, /data\/research\.sqlite/); assert.match(runner, /127\.0\.0\.1:20080\/search/); @@ -32,3 +45,42 @@ test('Deep Search production runtime is isolated from Portal releases', () => { assert.match(release, /launchctl bootout.*label/); assert.doesNotMatch(release, /release-portal-runtime-prod/); }); + +test('Deep Search runner resolves the physical release behind current symlink', (t) => { + const runtimeBase = mkdtempSync(path.join(tmpdir(), 'deep-search-runner-')); + t.after(() => rmSync(runtimeBase, { recursive: true, force: true })); + const releaseDir = path.join(runtimeBase, 'releases', 'r1'); + mkdirSync(path.join(releaseDir, 'scripts'), { recursive: true }); + mkdirSync(path.join(runtimeBase, 'shared'), { recursive: true }); + copyFileSync( + path.join(root, 'scripts', 'run-deep-search-prod.sh'), + path.join(releaseDir, 'scripts', 'run-deep-search-prod.sh'), + ); + writeFileSync(path.join(releaseDir, 'deep-search-server.mjs'), ''); + writeFileSync( + path.join(runtimeBase, 'shared', '.env'), + 'TKMIND_DEEP_SEARCH_SECRET=test-secret\n', + ); + const fakeNode = path.join(runtimeBase, 'fake-node.sh'); + writeFileSync(fakeNode, '#!/bin/sh\nprintf "%s\\n" "$1"\n'); + chmodSync(fakeNode, 0o755); + symlinkSync(releaseDir, path.join(runtimeBase, 'current')); + + const result = spawnSync( + '/bin/bash', + [path.join(runtimeBase, 'current', 'scripts', 'run-deep-search-prod.sh')], + { + encoding: 'utf8', + env: { + ...process.env, + DEEP_SEARCH_RUNTIME_BASE: runtimeBase, + NODE_BIN: fakeNode, + }, + }, + ); + assert.equal(result.status, 0, result.stderr); + assert.equal( + result.stdout.trim(), + path.join(realpathSync(releaseDir), 'deep-search-server.mjs'), + ); +}); diff --git a/scripts/run-deep-search-prod.sh b/scripts/run-deep-search-prod.sh index 842538e..309e3b2 100644 --- a/scripts/run-deep-search-prod.sh +++ b/scripts/run-deep-search-prod.sh @@ -1,7 +1,8 @@ #!/usr/bin/env bash set -euo pipefail -RUNTIME_ROOT="$(cd "$(dirname "$0")/.." && pwd)" +SCRIPT_DIR="$(cd -P "$(dirname "$0")" && pwd -P)" +RUNTIME_ROOT="$(cd -P "${SCRIPT_DIR}/.." && pwd -P)" RUNTIME_BASE="${DEEP_SEARCH_RUNTIME_BASE:-/Users/john/Project/deep-search-runtime}" ENV_FILE="${DEEP_SEARCH_ENV_FILE:-${RUNTIME_BASE}/shared/.env}"