mirror of
https://github.com/dtzp555-max/ocp.git
synced 2026-07-21 21:15:09 +00:00
Follow-up cleanup from #115's review. isLoopbackBind was defined in server.mjs and copy-pasted into test-features.mjs (with a "keep in sync" comment, because importing server.mjs would run server.listen()). Extracted to a new importable lib/net.mjs; server.mjs and the test now import the one definition, removing the drift surface. Pure refactor — the function body is byte-identical to the prior server.mjs version, the TUI LAN-gate call site is unchanged, and the 8 isLoopbackBind truth-table tests now exercise the real shared function. 181 tests pass. ALIGNMENT.md: touches server.mjs but adds/removes no operation — it relocates an existing (#115) helper into a module. cli.js citation N/A under Rule 2. Independent fresh-context reviewer (opus): APPROVE (Iron Rule 10) — byte-identical body, exactly one definition, wiring + scope correct, no test dropped, scope clean. Closes #125. Co-authored-by: dtzp555 <dtzp555@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,9 @@
|
|||||||
|
// OCP network helpers — shared so server.mjs and tests use one definition. (issue #125)
|
||||||
|
|
||||||
|
// A bind address is "loopback" only if it cannot be reached from another host.
|
||||||
|
// Any other address (0.0.0.0, ::, a concrete LAN/Tailscale IP, etc.) is
|
||||||
|
// network-exposed and must trigger the TUI LAN gate.
|
||||||
|
export function isLoopbackBind(addr) {
|
||||||
|
return addr === "127.0.0.1" || addr === "::1" || addr === "localhost" ||
|
||||||
|
addr === "::ffff:127.0.0.1" || /^127\./.test(addr);
|
||||||
|
}
|
||||||
+1
-8
@@ -36,6 +36,7 @@ import { dirname, join } from "node:path";
|
|||||||
import { homedir } from "node:os";
|
import { homedir } from "node:os";
|
||||||
import { validateKey, recordUsage, getUsageByKey, getUsageTimeline, getRecentUsage, createKey, listKeys, revokeKey, closeDb, checkQuota, updateKeyQuota, getKeyQuota, findKey, cacheHash, getCachedResponse, setCachedResponse, clearCache, getCacheStats, hasCacheControl, singleflight, getInflightStats } from "./keys.mjs";
|
import { validateKey, recordUsage, getUsageByKey, getUsageTimeline, getRecentUsage, createKey, listKeys, revokeKey, closeDb, checkQuota, updateKeyQuota, getKeyQuota, findKey, cacheHash, getCachedResponse, setCachedResponse, clearCache, getCacheStats, hasCacheControl, singleflight, getInflightStats } from "./keys.mjs";
|
||||||
import { DEFAULT_PORT } from "./lib/constants.mjs";
|
import { DEFAULT_PORT } from "./lib/constants.mjs";
|
||||||
|
import { isLoopbackBind } from "./lib/net.mjs";
|
||||||
import { runTuiTurn, reapStaleTuiSessions } from "./lib/tui/session.mjs";
|
import { runTuiTurn, reapStaleTuiSessions } from "./lib/tui/session.mjs";
|
||||||
|
|
||||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||||
@@ -299,14 +300,6 @@ const TUI_CWD = process.env.OCP_TUI_CWD || `${process.env.HOME}/.ocp-tui/work`
|
|||||||
const TUI_HOME = process.env.OCP_TUI_HOME || process.env.HOME;
|
const TUI_HOME = process.env.OCP_TUI_HOME || process.env.HOME;
|
||||||
const TUI_ENTRYPOINT = process.env.OCP_TUI_ENTRYPOINT || "cli"; // cli|auto|off — see ADR 0007
|
const TUI_ENTRYPOINT = process.env.OCP_TUI_ENTRYPOINT || "cli"; // cli|auto|off — see ADR 0007
|
||||||
|
|
||||||
// A bind address is "loopback" only if it cannot be reached from another host.
|
|
||||||
// Any other address (0.0.0.0, ::, a concrete LAN/Tailscale IP, etc.) is
|
|
||||||
// network-exposed and must trigger the TUI LAN gate. (issue #115)
|
|
||||||
function isLoopbackBind(addr) {
|
|
||||||
return addr === "127.0.0.1" || addr === "::1" || addr === "localhost" ||
|
|
||||||
addr === "::ffff:127.0.0.1" || /^127\./.test(addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// SECURITY fail-loud: TUI-mode is incompatible with any configuration that allows
|
// SECURITY fail-loud: TUI-mode is incompatible with any configuration that allows
|
||||||
// non-operator prompts to reach the interactive claude session. Three cases:
|
// non-operator prompts to reach the interactive claude session. Three cases:
|
||||||
// 1. AUTH_MODE=multi — guest/anonymous keys can submit prompts.
|
// 1. AUTH_MODE=multi — guest/anonymous keys can submit prompts.
|
||||||
|
|||||||
+3
-9
@@ -4,6 +4,7 @@
|
|||||||
* Tests database layer functions directly — no server needed.
|
* Tests database layer functions directly — no server needed.
|
||||||
*/
|
*/
|
||||||
import { getDb, createKey, listKeys, validateKey, recordUsage, checkQuota, updateKeyQuota, getKeyQuota, findKey, cacheHash, getCachedResponse, setCachedResponse, clearCache, getCacheStats, closeDb, hasCacheControl, singleflight, getInflightStats } from "./keys.mjs";
|
import { getDb, createKey, listKeys, validateKey, recordUsage, checkQuota, updateKeyQuota, getKeyQuota, findKey, cacheHash, getCachedResponse, setCachedResponse, clearCache, getCacheStats, closeDb, hasCacheControl, singleflight, getInflightStats } from "./keys.mjs";
|
||||||
|
import { isLoopbackBind } from "./lib/net.mjs";
|
||||||
import { createHash } from "node:crypto";
|
import { createHash } from "node:crypto";
|
||||||
import { strict as assert } from "node:assert";
|
import { strict as assert } from "node:assert";
|
||||||
import { unlinkSync } from "node:fs";
|
import { unlinkSync } from "node:fs";
|
||||||
@@ -1798,17 +1799,10 @@ test("KEY_NAME_RE: 65-char string → invalid", () => {
|
|||||||
assert.ok(!KEY_NAME_RE.test("x".repeat(65)));
|
assert.ok(!KEY_NAME_RE.test("x".repeat(65)));
|
||||||
});
|
});
|
||||||
|
|
||||||
// ── isLoopbackBind helper (issue #115) ──────────────────────────────────────
|
// ── isLoopbackBind helper (issue #115, extracted to lib/net.mjs via #125) ──────
|
||||||
// MIRRORS server.mjs isLoopbackBind — copied verbatim to avoid importing server.mjs
|
// Tests the imported lib/net.mjs helper — the real shared definition used by server.mjs.
|
||||||
// (top-level server.listen() would start a live HTTP server).
|
|
||||||
// Keep in sync with the definition in server.mjs above the TUI gate block.
|
|
||||||
console.log("\nisLoopbackBind helper (issue #115):");
|
console.log("\nisLoopbackBind helper (issue #115):");
|
||||||
|
|
||||||
function isLoopbackBind(addr) {
|
|
||||||
return addr === "127.0.0.1" || addr === "::1" || addr === "localhost" ||
|
|
||||||
addr === "::ffff:127.0.0.1" || /^127\./.test(addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
test("isLoopbackBind: '127.0.0.1' → true", () => {
|
test("isLoopbackBind: '127.0.0.1' → true", () => {
|
||||||
assert.equal(isLoopbackBind("127.0.0.1"), true);
|
assert.equal(isLoopbackBind("127.0.0.1"), true);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user