fix(db): keep a read-only database read-only - #547
Merged
Merged
Conversation
Opening the database set its file mode to 600, which gave the owner back the write permission on a database made read-only, so every later process wrote into it. Only access for other users is removed now; the owner's permissions are left as they are. Closes #520
A WAL database cannot be read without creating its -shm file, so a database in a folder the owner made read-only is refused with an error; opening it used to work only by making the folder writable again.
Everywhere MeMesh sets permissions on its data folder and files (the database and its -wal/-shm, every hook's database connection, `serve --host`, the remote token, the install id, the config, the message router and the Codex companion), it now only removes group and other access and keeps the owner's bits as they are. Before, a fixed 0600/0700 gave a read-only database, folder or token its owner write bit back. A folder or token MeMesh creates is still created private (0700 / 0600). - A -wal or -shm whose owner bits differ from the database's in a way SQLite would change or trip over is refused before anything is opened, with the chmod command to run; MeMesh never changes a sidecar's owner bits itself. This applies to the CLI, MCP, HTTP, every hook including read-only opens, and `npm run audit:memory`, and follows a symlinked database path to the real files. - A database opened read-only says which files to make writable to write to it again, and `memesh doctor` shows it as read-only. - A read-only folder whose -wal and -shm exist is opened read-only and read, as SQLite supports; writes are refused. If a sidecar is missing, the error names the folder and the command to run. - An existing remote token is read as it is; a read-only one stays read-only. - A permission change that cannot be applied prints the file and the command to run, once; a folder that belongs to another user is named as such instead. - The router and the Codex companion stop with a one-line reason on a read-only data folder or companion lifecycle folder instead of making it writable. - `memesh doctor` shows MeMesh's own reason and command for a permission error, including the -wal/-shm, instead of suggesting to move the database away; `doctor --fix` no longer sets the database to 600. Refs #520
- A database path that is a symlink is judged by the real file's folder: a read-only folder holding only the link no longer refuses a database whose -wal/-shm sit, writable, beside the real file. - The maintainer measurement scripts under scripts/audit check the -wal/-shm modes before they open a database, as memesh itself does. - `memesh doctor` no longer suggests a full disk for a permission problem MeMesh refused on: Hook activity and Capture liveness point to the Database row and its chmod command. - A file or folder owned by another user is answered with "Point MEMESH_DB_PATH at a database you own, in a folder you own." Refs #520
…lone - A read-only file or folder that belongs to another user is answered with "point MEMESH_DB_PATH at a database you own, in a folder you own" instead of a chmod command the user cannot run. Root, which can change any file, still gets the chmod. - For a symlinked database path only the link's folder loses group and other access; the real database's folder is checked but never changed, since it may be a folder the user shares on purpose. - `memesh doctor` lists the real file's -wal/-shm when the database path is a symlink, and prints "Run:" only in front of a command. Refs #520
…-readonly # Conflicts: # CHANGELOG.md # dist/mcp/THIRD_PARTY_NOTICES.txt # dist/mcp/server.js.map # dist/skills-manifest.json # dist/transports/cli/cli.js.map # scripts/hooks/pre-edit-recall.js # scripts/hooks/session-start.js # scripts/hooks/stop-message-gate.js
Root is never told a file belongs to another user: it is given the chmod, which root can run. A test now holds that, with a stubbed uid. Two tests read the -wal before they check its size or mode, so the read no longer follows a check of the same file. Refs #520
… yours When a -wal or -shm has different owner permissions from the database and belongs to another user, the refusal told the user to chmod a file they cannot change. It now keeps the refusal and its code but says to point MEMESH_DB_PATH at a database of their own, as the other permission errors already do. Refs #520
An empty -wal with more owner permissions, and a mismatched -wal next to a database that belongs to another user, now each have a test for the "database you own" advice. Refs #520
…-readonly # Conflicts: # CHANGELOG.md # dist/db.d.ts.map # dist/db.js # dist/db.js.map # dist/mcp/THIRD_PARTY_NOTICES.txt # dist/mcp/server.js # dist/mcp/server.js.map # dist/transports/cli/cli.d.ts.map # dist/transports/cli/cli.js # dist/transports/cli/cli.js.map # src/db.ts
…-readonly # Conflicts: # scripts/audit/memory-invariants.mjs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #520.
Opening a database you made read-only (for example
chmod 444on a snapshot or backup) no longer makes it writable. memesh set the database file, its-wal/-shmfiles and its folder to fixed modes (600/700) on every open, which gave the owner back the write permission, so every later hook, CLI or MCP process wrote into it. It now only removes access for other users and leaves the owner's permissions as they are. A world-readable database is still tightened to owner-only.A database whose folder is also read-only cannot be opened (a WAL database needs to create its
-shmfile), so it is now refused with an error instead of being made writable.Tests
New
tests/db-readonly-mode.test.ts: a444database stays non-writable across two opens, a644database is still tightened to600, and a read-only database in a read-only folder is refused with nothing made writable. The first two fail on the previous code.npm run verify: green.