Local dev setup; fix mirror volume ownership and a test footgun
Adds docker-compose.override.yml (local-only: publishes the server on 127.0.0.1:8080 and Postgres on 127.0.0.1:55432, crawls on demand) and docs/LOCAL.md covering the stack, Claude Code registration over both transports, the CLI, and the test suites. Two bugs that only running the real container could find: The mirror volume was root-owned while the container runs as node, so every file write failed with EACCES. Docker initialises a named volume from the image directory including its ownership, so the fix is to create /data/mirror owned by node in the image. This was easy to miss because the indexer records a per-file failure rather than crashing — the crawl "succeeded" with 4 skipped. Earlier direct-node testing missed it entirely by writing to a scratch dir owned by the developer. The store tests TRUNCATE, and pointing TEST_DATABASE_URL at the dev database put their fixtures into real data. They now refuse any database whose name does not contain "test". Verified against the rebuilt container: 4 files mirrored, image-only PDF detection firing in the real pipeline, both transports showing ✔ Connected in `claude mcp list`, and a whoami tool call driven end to end through `claude -p`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -8,7 +8,23 @@ import type { Snapshot } from '../src/core/crawl.ts';
|
||||
* are entirely SQL, so a mock would test nothing. Skipped when TEST_DATABASE_URL
|
||||
* is unset so `npm test` stays offline by default.
|
||||
*/
|
||||
const URL = process.env.TEST_DATABASE_URL;
|
||||
const DB_URL = process.env.TEST_DATABASE_URL;
|
||||
|
||||
/**
|
||||
* These tests TRUNCATE. Pointing them at a real database destroys it — which
|
||||
* happened once during development, when TEST_DATABASE_URL was aimed at the dev
|
||||
* instance and the fixtures ended up in live data. Requiring "test" in the
|
||||
* database name makes that mistake impossible to repeat by accident.
|
||||
*/
|
||||
function assertDisposable(url: string): void {
|
||||
const name = new globalThis.URL(url).pathname.replace(/^\//, '');
|
||||
if (!/test/i.test(name)) {
|
||||
throw new Error(
|
||||
`Refusing to run: TEST_DATABASE_URL points at database "${name}", which is not obviously ` +
|
||||
`disposable. These tests TRUNCATE. Use a database with "test" in its name.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function snapshot(courses: { id: string; title: string; boardText?: string; files?: { id: string; name: string; size: number }[] }[]): Snapshot {
|
||||
return {
|
||||
@@ -38,11 +54,12 @@ function snapshot(courses: { id: string; title: string; boardText?: string; file
|
||||
};
|
||||
}
|
||||
|
||||
describe('Store', { skip: URL ? false : 'set TEST_DATABASE_URL to run' }, () => {
|
||||
describe('Store', { skip: DB_URL ? false : 'set TEST_DATABASE_URL to run' }, () => {
|
||||
let store: Store;
|
||||
|
||||
before(async () => {
|
||||
const opened = await Store.open(URL);
|
||||
assertDisposable(DB_URL!);
|
||||
const opened = await Store.open(DB_URL);
|
||||
assert.ok(opened, 'store should open');
|
||||
store = opened;
|
||||
// Start from a clean slate so generation ids are predictable.
|
||||
|
||||
Reference in New Issue
Block a user