Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3fd1db8c2f | |||
| 6573c6bee0 | |||
| 22a45f34f5 | |||
| 25c09f1e8f |
@@ -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,12 +25,15 @@ 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/);
|
||||
|
||||
const installer = read('scripts/install-deep-search-runtime-prod.sh');
|
||||
assert.match(installer, /cn\.tkmind\.memind-deep-search/);
|
||||
assert.match(installer, /<string>\/bin\/bash<\/string>/);
|
||||
assert.match(installer, /<key>WorkingDirectory<\/key><string>\$\{RUNTIME_BASE\}<\/string>/);
|
||||
assert.match(installer, /chmod 600/);
|
||||
assert.match(installer, /openssl rand -hex 32/);
|
||||
|
||||
@@ -27,5 +42,45 @@ test('Deep Search production runtime is isolated from Portal releases', () => {
|
||||
assert.match(release, /CONFIRMED_CI_SHA/);
|
||||
assert.match(release, /shasum -a 256/);
|
||||
assert.match(release, /rollback/);
|
||||
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'),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -52,8 +52,11 @@ cat > "${PLIST}" <<EOF
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0"><dict>
|
||||
<key>Label</key><string>${LABEL}</string>
|
||||
<key>ProgramArguments</key><array><string>${RUNTIME_BASE}/current/scripts/run-deep-search-prod.sh</string></array>
|
||||
<key>WorkingDirectory</key><string>${RUNTIME_BASE}/current</string>
|
||||
<key>ProgramArguments</key><array>
|
||||
<string>/bin/bash</string>
|
||||
<string>${RUNTIME_BASE}/current/scripts/run-deep-search-prod.sh</string>
|
||||
</array>
|
||||
<key>WorkingDirectory</key><string>${RUNTIME_BASE}</string>
|
||||
<key>EnvironmentVariables</key><dict>
|
||||
<key>DEEP_SEARCH_RUNTIME_BASE</key><string>${RUNTIME_BASE}</string>
|
||||
<key>NODE_BIN</key><string>${NODE_BIN}</string>
|
||||
@@ -74,7 +77,7 @@ launchctl enable "${GUI}/${LABEL}"
|
||||
launchctl kickstart -k "${GUI}/${LABEL}"
|
||||
|
||||
for _ in $(seq 1 30); do
|
||||
if curl -fsS --max-time 2 "http://127.0.0.1:20100/health" >/dev/null; then
|
||||
if curl -fsS --max-time 2 "http://127.0.0.1:20100/health" >/dev/null 2>&1; then
|
||||
exit 0
|
||||
fi
|
||||
sleep 1
|
||||
|
||||
@@ -143,6 +143,7 @@ shasum -a 256 -c "$(basename "${sha_file}")"
|
||||
tar -xzf "${archive}" -C "${release_dir}"
|
||||
|
||||
rollback() {
|
||||
launchctl bootout "${gui}/${label}" >/dev/null 2>&1 || true
|
||||
if [[ -n "${previous_target}" && -d "${previous_target}" ]]; then
|
||||
ln -sfn "${previous_target}" "${current_link}"
|
||||
else
|
||||
@@ -150,9 +151,10 @@ rollback() {
|
||||
fi
|
||||
if [[ -f "${backup_dir}/launchagent.plist" ]]; then
|
||||
cp "${backup_dir}/launchagent.plist" "${plist}"
|
||||
launchctl bootout "${gui}/${label}" >/dev/null 2>&1 || true
|
||||
launchctl bootstrap "${gui}" "${plist}" >/dev/null 2>&1 || true
|
||||
launchctl kickstart -k "${gui}/${label}" >/dev/null 2>&1 || true
|
||||
else
|
||||
rm -f "${plist}"
|
||||
fi
|
||||
}
|
||||
trap rollback ERR
|
||||
|
||||
@@ -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}"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user