@dotdrelle/wiki-manager 0.11.7 → 0.11.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/core/mcp.js +1 -1
- package/src/runtime/lifecycle.js +19 -2
- package/src/runtime/server.js +3 -0
- package/src/runtime/server.test.js +44 -0
package/package.json
CHANGED
package/src/core/mcp.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from 'node:fs';
|
|
2
2
|
import { managerEnvFile, managerMcpEndpointsFile, readEnvFile } from './env.js';
|
|
3
3
|
|
|
4
|
-
const WIKI_MANAGER_VERSION = '0.11.
|
|
4
|
+
const WIKI_MANAGER_VERSION = '0.11.9';
|
|
5
5
|
|
|
6
6
|
function envValue(key) {
|
|
7
7
|
const filePath = managerEnvFile();
|
package/src/runtime/lifecycle.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { execFile, spawn } from 'node:child_process';
|
|
2
2
|
import { dirname, resolve } from 'node:path';
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
|
-
import {
|
|
4
|
+
import { activeCacertPath } from '../core/cacert.js';
|
|
5
|
+
import { checkRuntimeHealth, postRuntimeShutdown, runtimeUrlFromEnv } from './client.js';
|
|
5
6
|
import { defaultRuntimeStateDir } from '../core/env.js';
|
|
6
7
|
import { resolveRuntimeAuthToken, runtimeTokenFromEnv } from './auth.js';
|
|
7
8
|
|
|
@@ -42,7 +43,15 @@ export async function ensureRuntime({
|
|
|
42
43
|
const auth = resolveRuntimeAuthToken({ host, stateDir });
|
|
43
44
|
if (auth.token) process.env.WIKI_MANAGER_RUNTIME_TOKEN = auth.token;
|
|
44
45
|
const existing = await runtimeHealthOrNull(url, auth.token);
|
|
45
|
-
if (existing)
|
|
46
|
+
if (existing) {
|
|
47
|
+
const expectedCacertPath = activeCacertPath();
|
|
48
|
+
const actualCacertPath = existing.cacertPath ? resolve(existing.cacertPath) : null;
|
|
49
|
+
if (actualCacertPath === expectedCacertPath) {
|
|
50
|
+
return { url, started: false, health: existing, token: auth.token, tokenPath: auth.tokenPath };
|
|
51
|
+
}
|
|
52
|
+
await postRuntimeShutdown({ url, token: auth.token });
|
|
53
|
+
await waitForRuntimeShutdown(url, auth.token, 2500);
|
|
54
|
+
}
|
|
46
55
|
|
|
47
56
|
const runtimeNode = await assertRuntimeNode();
|
|
48
57
|
const child = spawn(runtimeNode.executable, [
|
|
@@ -75,6 +84,14 @@ export async function ensureRuntime({
|
|
|
75
84
|
throw new Error(`Runtime did not become healthy at ${url}`);
|
|
76
85
|
}
|
|
77
86
|
|
|
87
|
+
async function waitForRuntimeShutdown(url, token, timeoutMs) {
|
|
88
|
+
const deadline = Date.now() + timeoutMs;
|
|
89
|
+
while (Date.now() < deadline) {
|
|
90
|
+
if (!await runtimeHealthOrNull(url, token)) return;
|
|
91
|
+
await new Promise((resolveDelay) => setTimeout(resolveDelay, 100));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
78
95
|
export async function runtimeHealthOrNull(url = runtimeUrlFromEnv(), token = runtimeTokenFromEnv()) {
|
|
79
96
|
try {
|
|
80
97
|
return await checkRuntimeHealth({ url, token });
|
package/src/runtime/server.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createServer } from 'node:http';
|
|
2
2
|
import { randomUUID, timingSafeEqual } from 'node:crypto';
|
|
3
3
|
import { createAgentEvent, dispatchAgentEvent } from '../core/agentEvents.js';
|
|
4
|
+
import { activeCacertPath } from '../core/cacert.js';
|
|
4
5
|
import { normalizePlanPatch, rebasePlanPatch } from '../core/planPatch.js';
|
|
5
6
|
import { validateContractInDev } from '../contracts/schemas.js';
|
|
6
7
|
import { runtimeTokenFromEnv } from './auth.js';
|
|
@@ -55,6 +56,8 @@ export function startRuntimeServer({
|
|
|
55
56
|
status: context?.running ? 'running' : 'idle',
|
|
56
57
|
workspace: context?.workspace ?? workspace ?? null,
|
|
57
58
|
dbPath: store.dbPath,
|
|
59
|
+
cacertPath: activeCacertPath(),
|
|
60
|
+
nodeExtraCaCerts: process.env.NODE_EXTRA_CA_CERTS ?? null,
|
|
58
61
|
});
|
|
59
62
|
return;
|
|
60
63
|
}
|
|
@@ -46,6 +46,50 @@ test('runtime server checks bearer and x-runtime-token credentials', async (t) =
|
|
|
46
46
|
}
|
|
47
47
|
});
|
|
48
48
|
|
|
49
|
+
test('runtime health exposes active CA certificate environment', async (t) => {
|
|
50
|
+
const previousCacert = process.env.WIKI_MANAGER_CACERT_PATH;
|
|
51
|
+
const previousNodeExtraCaCerts = process.env.NODE_EXTRA_CA_CERTS;
|
|
52
|
+
process.env.WIKI_MANAGER_CACERT_PATH = '/tmp/wiki-manager-test-ca.pem';
|
|
53
|
+
process.env.NODE_EXTRA_CA_CERTS = '/tmp/wiki-manager-test-ca.pem';
|
|
54
|
+
let handle;
|
|
55
|
+
try {
|
|
56
|
+
handle = await startRuntimeServer({
|
|
57
|
+
host: '127.0.0.1',
|
|
58
|
+
port: 0,
|
|
59
|
+
token: 'runtime-secret',
|
|
60
|
+
store: {
|
|
61
|
+
dbPath: ':memory:',
|
|
62
|
+
getState: () => ({ status: 'idle' }),
|
|
63
|
+
listEvents: () => [],
|
|
64
|
+
},
|
|
65
|
+
session: {},
|
|
66
|
+
run: async () => {},
|
|
67
|
+
});
|
|
68
|
+
} catch (err) {
|
|
69
|
+
if (err?.code === 'EPERM') {
|
|
70
|
+
t.skip('network listen is not permitted in this sandbox');
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
throw err;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
const response = await fetch(`http://127.0.0.1:${handle.port}/health`, {
|
|
78
|
+
headers: { authorization: 'Bearer runtime-secret' },
|
|
79
|
+
});
|
|
80
|
+
assert.equal(response.status, 200);
|
|
81
|
+
const body = await response.json();
|
|
82
|
+
assert.equal(body.cacertPath, '/tmp/wiki-manager-test-ca.pem');
|
|
83
|
+
assert.equal(body.nodeExtraCaCerts, '/tmp/wiki-manager-test-ca.pem');
|
|
84
|
+
} finally {
|
|
85
|
+
await handle.close();
|
|
86
|
+
if (previousCacert === undefined) delete process.env.WIKI_MANAGER_CACERT_PATH;
|
|
87
|
+
else process.env.WIKI_MANAGER_CACERT_PATH = previousCacert;
|
|
88
|
+
if (previousNodeExtraCaCerts === undefined) delete process.env.NODE_EXTRA_CA_CERTS;
|
|
89
|
+
else process.env.NODE_EXTRA_CA_CERTS = previousNodeExtraCaCerts;
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
49
93
|
test('runtime server shutdown endpoint closes the listener', async (t) => {
|
|
50
94
|
let handle;
|
|
51
95
|
try {
|