Files
routstrd/tests/daemon/config-store.scenario.ts
T
redshift 99f55d3bae chore(wallet): remove the dead legacy cocod client
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.
2026-10-02 16:59:42 +08:00

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");