mirror of
https://github.com/Routstr/routstrd.git
synced 2026-10-05 12:28:23 +00:00
The external `cocod` binary was replaced by the in-process Coco wallet long ago, but its HTTP/unix-socket client kept shipping ~280 lines of unreachable code next to the wallet contract. Remove it: - delete `createCocodClient` (spawns `cocod init`, talks over a unix socket, takes a cross-process startup lock) and its helpers `resolveCocodExecutable`, `isCocodInstalled`, `normalizeBalances` and `CocodBalanceOutput`. None of them are reachable from production or from tests; `isCocodInstalled` had no callers at all. - drop the `options.walletClient || createCocodClient(...)` fallback in `createWalletAdapter`. The daemon always passes the in-process client built by `createCocoClient()`, so `walletClient` is now required and the adapter can no longer silently spawn an external binary. - drop the vestigial `cocodPath` config key, which only ever fed that fallback. - delete the "legacy cocod client NPC passthroughs" test block, which covered only the deleted client. The shared wallet contract moves from `cocod-client.ts` to `wallet-client.ts` and loses its `Cocod` prefixes (`WalletClient`, `WalletRuntimeState`, `WalletHttpError`) — none of it describes cocod any more. `WalletRuntimeState` avoids colliding with the existing `WalletState` in `wallet-state.ts`. Legacy cocod *migration* code is deliberately untouched: `stopLegacyCocod`, `assertLegacyCocodNotRunning`, `claimLegacyCocodPidFile`, `migration.ts` and the `legacyCocod*` paths still migrate an existing `~/.cocod` wallet and fence off a running external daemon. Net -456 lines. Existing configs that still contain `cocodPath` load unchanged (unknown keys are ignored) — the key is just no longer written.
116 lines
3.6 KiB
TypeScript
116 lines
3.6 KiB
TypeScript
// Scenario runner for config-store.perms.test.ts — executed as a standalone
|
|
// bun process with ROUTSTRD_DIR set before module evaluation. Not a test file.
|
|
import {
|
|
chmodSync,
|
|
existsSync,
|
|
readdirSync,
|
|
statSync,
|
|
writeFileSync,
|
|
} from "fs";
|
|
|
|
const { CONFIG_DIR, CONFIG_FILE } = await import("../../src/utils/config");
|
|
const {
|
|
ensureDirs,
|
|
ensureDirsSync,
|
|
loadDaemonConfig,
|
|
loadDaemonConfigSync,
|
|
saveDaemonConfig,
|
|
REQUESTS_DIR,
|
|
} = await import("../../src/daemon/config-store");
|
|
|
|
const modeOf = (p: string): number => statSync(p).mode & 0o777;
|
|
|
|
const baseConfig = {
|
|
port: 8008,
|
|
host: "127.0.0.1",
|
|
provider: null,
|
|
};
|
|
|
|
function assert(cond: unknown, msg: string): void {
|
|
if (!cond) {
|
|
console.error(`ASSERT-FAIL: ${msg}`);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
const scenario = process.argv[2];
|
|
|
|
switch (scenario) {
|
|
case "fresh-install": {
|
|
assert(loadDaemonConfigSync().autoModelPath === false, "autoModelPath must default to false");
|
|
saveDaemonConfig({
|
|
...baseConfig,
|
|
autoModelPath: true,
|
|
nsec: "nsec1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
|
|
});
|
|
assert(modeOf(CONFIG_DIR) === 0o700, `dir mode ${modeOf(CONFIG_DIR).toString(8)} != 700`);
|
|
assert(modeOf(CONFIG_FILE) === 0o600, `file mode ${modeOf(CONFIG_FILE).toString(8)} != 600`);
|
|
assert(
|
|
readdirSync(CONFIG_DIR).filter((f) => f.endsWith(".tmp")).length === 0,
|
|
"temp file left behind",
|
|
);
|
|
const loaded = await loadDaemonConfig();
|
|
assert(
|
|
loaded.nsec === "nsec1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
|
|
"nsec round-trip failed",
|
|
);
|
|
assert(loaded.port === 8008, "port round-trip failed");
|
|
assert(loaded.autoModelPath === true, "autoModelPath round-trip failed");
|
|
|
|
await ensureDirs();
|
|
assert(modeOf(CONFIG_DIR) === 0o700, "ensureDirs dir mode");
|
|
assert(modeOf(REQUESTS_DIR) === 0o700, "ensureDirs requests dir mode");
|
|
break;
|
|
}
|
|
|
|
case "repair-perms": {
|
|
// Simulate an install written by the vulnerable version.
|
|
ensureDirsSync();
|
|
writeFileSync(CONFIG_FILE, JSON.stringify(baseConfig), { mode: 0o644 });
|
|
chmodSync(CONFIG_DIR, 0o755);
|
|
chmodSync(CONFIG_FILE, 0o644);
|
|
assert(modeOf(CONFIG_FILE) === 0o644, "setup: file not 0644");
|
|
|
|
// Load repairs the file mode...
|
|
loadDaemonConfigSync();
|
|
assert(modeOf(CONFIG_FILE) === 0o600, "load did not repair file mode");
|
|
|
|
// ...and the next save repairs the directory mode too.
|
|
chmodSync(CONFIG_DIR, 0o755);
|
|
saveDaemonConfig({ ...baseConfig, port: 9009 });
|
|
assert(modeOf(CONFIG_DIR) === 0o700, "save did not repair dir mode");
|
|
assert(modeOf(CONFIG_FILE) === 0o600, "save did not keep file mode");
|
|
assert(loadDaemonConfigSync().port === 9009, "save did not persist port");
|
|
break;
|
|
}
|
|
|
|
case "write-failure": {
|
|
// Turn the config dir into a regular file: mkdir fails and no temp write
|
|
// can succeed, so saveDaemonConfig must surface the error synchronously.
|
|
writeFileSync(process.env.ROUTSTRD_DIR!, "blocked");
|
|
let threw = false;
|
|
try {
|
|
saveDaemonConfig(baseConfig);
|
|
} catch {
|
|
threw = true;
|
|
}
|
|
assert(threw, "saveDaemonConfig did not throw on unwritable target");
|
|
break;
|
|
}
|
|
|
|
case "corrupt-json": {
|
|
ensureDirsSync();
|
|
writeFileSync(CONFIG_FILE, "{ not json");
|
|
const loaded = await loadDaemonConfig();
|
|
assert(loaded.port === 8008, "did not fall back to defaults");
|
|
assert(existsSync(CONFIG_FILE), "config file vanished");
|
|
break;
|
|
}
|
|
|
|
default:
|
|
console.error(`unknown scenario: ${scenario}`);
|
|
process.exit(2);
|
|
}
|
|
|
|
console.log("SCENARIO-OK");
|