fix(p2p): write the generated man-p2p runtime config with mode 0600 - #37
Merged
newfish merged 1 commit intoSep 15, 2026
Conversation
The generated man-p2p-runtime-config.toml embeds the fully resolved man-p2p config, including plaintext third-party RPC credentials, but fs.writeFileSync was called without a mode, so the file landed as 0o666 & ~umask (0644 under the usual umask 0022) - wider than the sibling identity.key (0600). Pass an explicit 0o600 mode, and chmod afterwards because writeFileSync's mode only applies when the file is created (existing installs already have a leaked 0644 runtime config). The user-provided base config is untouched: the no-override early return is unchanged. Adds tests/p2pRuntimeConfigMode.test.mjs (fresh write, pre-existing 0644 file, untouched base config, non-vacuous mode assertion) and whitelists it in .gitignore.
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.
Symptom
When the man-p2p config needs a local override, IDBots generates
man-p2p-runtime-config.tomlinside the man-p2p data dir. That file is the fullyresolved man-p2p config — it embeds the base config verbatim, including
plaintext third-party RPC credentials — yet it was written through
fs.writeFileSyncwithout an explicit mode, so it landed at0o666 & ~umask= 0644 (
-rw-r--r--) under the common umask0022.The only credential-bearing file in that directory was therefore the loosest one;
its sibling
identity.keyis created0600(-rw-------) by the same code base.Reproducible before/after on an isolated data dir (
umask 0022):The original leak was also observed on a real install (
$HOME/Library/Application Support/IDBots/man-p2p/man-p2p-runtime-config.toml, 1362 bytes) — v1 of this bodyquoted that
statas-rw-r--r--. That particular capture is no longerre-verifiable: while the fix was still uncommitted, that live file's mode was
changed to
0600out-of-band by the machine operator as an immediate localstop-gap while this fix was still uncommitted (inode
ctime12:22:17,mtimeunchanged at 10:44:36 — a chmod, not a rewrite; the file's content was untouched). Treat the live
stat as narrative context only; the load-bearing evidence is the isolated
red/green below, which is reproducible at any time.
Root cause
src/main/services/p2pIndexerService.ts:470at62577cb1(v0.9.0):fs.writeFileSyncwithout an explicitmodeuses0o666 & ~umask; under umask0022that is 0644.Fix
Pass an explicit mode, and tighten the file afterwards:
Why the extra
chmodSync.fs.writeFileSyncappliesmodeonly when itcreates the file. On any existing installation the runtime config already
exists with 0644, so passing
modealone would fix new installs and silentlyleave every upgraded install still leaking credentials — the worst kind of
half-fix, because the symptom disappears from fresh test runs. The
chmodSyncmakes the post-condition unconditional: after
resolveRuntimeConfigPath()returns a runtime config path, that file is 0600. It touches exactly that one
file and nothing else (no directory sweep, no recursive chmod).
Change size: 1 file changed, 16 insertions(+), 1 deletion(-) in
src/main/services/p2pIndexerService.ts, plus one new test file and its.gitignorewhitelist line (this repo whitelists test files individually via!tests/<name>;tests/*is otherwise ignored).Scope
resolveMainConfigPath()) is never writtenand never
chmoded: when no override is needed, the early return at:466(baseline) still hands back
mainConfigPathand no runtime file is created.tests/p2pRuntimeConfigMode.test.mjspins both the content and the modeof the base config so this stays true.
Verification
New regression test:
tests/p2pRuntimeConfigMode.test.mjs. It loads thecompiled main-process module (
dist-electron/main/services/p2pIndexerService.js),so red/green was proven with a recompile in between, and the patch marker
RUNTIME_CONFIG_FILE_MODEwas used to prove the compiled artifact actuallychanged (not just the TypeScript source).
Tests (4):
0022a plainwriteFileSyncis observable as0644, so the mode assertion is not vacuous;
Red — source reverted to
62577cb1, recompiledGreen — patch applied, recompiled
Related existing suites, lint
Notes for reviewers
0600, not derived from the ambientumask: the file carries credentials, so it must be owner-only regardless of the
host umask.
(
man_base_data_pebble/stays0755,identity.keyis untouched).