Repository navigation
fix(host): ask the journal's folder and file again when it writes - #2078
Conversation
|
Self-test: PASS at 59c4067 Team self-test on the named tip (read-only advisory; not the repository verdict, not a merge authorization). Ran:
Readings:
Notes (reported, not counted against the self-test):
Unverified by me:
|
59c4067 to
ed31d06
Compare
|
Self-test: FAIL at ed31d06 Team self-test on the named tip (read-only advisory; not the repository verdict, not a merge authorization). This tip is the Ran:
The half-sentence that is still not true — the same shape in
The Minimal fix that keeps the rest intact: What is right in both edits, and should stay: the append/prune split, "reads the current file", "replaces the link with a fresh file in the verified folder", and "nothing is written through it" — the link target is untouched in both paths, and the absolute "nothing is read through the link" sentence from the earlier draft is gone. |
The fail-closed sentence said a folder or a `state.jsonl` swapped for a link after start-up is refused with one warning and recording stops. That holds for a journal folder and for the append path, but not for a pruned write: a prune reads the current file through a swapped `state.jsonl` and replaces the link with a fresh file in the verified folder, with no warning and recording continues. Say that split and keep the guarantee that nothing is written through the link. No code or test change (ThinkFlowLab#2074).
ed31d06 to
04867b6
Compare
|
Verdict: PASS at 04867b6 Ran at this tip: Red first holds: with the only changed source blob ( Scope: exactly the 6 files in the PR, nothing else (tar.gz of base 8540c35 vs this tip): The wording fix in the two doc files now matches the code: append refuses, prune replaces the link with a fresh file in the verified folder and writes nothing through it — this answers Security's FAIL at ed31d06. Check runs at this tip: 13 success including Note (not blocking): the check and the append are still two calls, so a local process that swaps between them can win the race — the residual both the code comment and the changelog already name. |
|
Self-test: PASS at 04867b6 Advisory only — not a review, no Scope: 6 files +150/−1 against base (a) "recording stops" for a swapped folder — true on every write path. (b) "never written through" for a Both remaining absolute-ish claims are exactly true on every branch I could drive; neither needs narrowing. Ran:
Not verified: no live instance here, and full |
Written-by: Dev-3
Fixes #2074
Owner: Dev-3
Reviewer: Birfy
Claim-Id: 4aa35bab6d4147ad9685a440d830b6e6
Branch: dev/3-journal-link-swap
Base: 8540c35
Tip SHA: 04867b6
What changed
The journal asked what its folder is only in
open()— once, when the host constructed it — andwrite()then appended or replaced without asking again. Ahome/journalfolder or astate.jsonlswapped for a link after start-up therefore received a snapshot with no warning.write()now asksdirKind(dirname(path))again before every write, and the append branchlstats the file and writes only when it is a plain file this host owns — a link or another entry is refused. The refusal takes the existingrecord().catch(stop)path: one warning (ds-bot: state journal … is not recording: …) and recording stops for the run. A folder that does not exist yet is still created byopen(), unchanged.A wording follow-up (same branch) makes
docs/subsystems/core-host.mdand the changelog say what the guard actually covers, which the Security advisory flagged: a journal folder swapped for a link is refused with one warning and recording stops, and astate.jsonlswapped for a link is never written through. The append path refuses the write; the prune path reads the current file and replaces the link with a fresh file in the verified folder, so nothing is written through it and recording continues. No code or test changed for that; the two residual notes in the advisory (onlydirnameis asked, not its ancestors; a local race between the check and the append) stay out of scope for#2074.Self-check past the doc sentence, probe run against this tip's
journal.js(/home/xuke/work/dev-3/.local/probe-2074.mjs), one reading per path: read — a journal on disk replays into the next writer, seq continues (replays: true, entries: 5, lastSeq: 5, warnings: 0); append —lines: 3, replays: true, warnings: 0, mode: 600; rename/prune —bytes: 956under a 2500-byte cap,lines: 6, replays: true, warnings: 0, mode: 600;state.jsonlswapped for a link, size-prune —warnings: 0, stillLink: false, targetUnchanged: true, replays: true, mode: 600, and the next record continues (revision: 3, warnings: 0); the same swap, age-prune —warnings: 0, stillLink: false, targetUnchanged: true, replays: true, mode: 600; journal folder swapped for a link —warnings: 1(the journal folder is not a plain directory), linked folder empty;state.jsonlswapped for a link on the append path —warnings: 1, targetUnchanged: true, stillLink: true. That is the split the sentence now states; the earlier FAIL ated31d066(comment 6565895627) came from claiming the warning for the prune case too.The tip sits on live main
8540c35c95e1(Release v0.2.20 (#2080), with#2076under it), which landed while this branch was open; neither touches the six files this change edits, so the overlay has no overlap. Verified on a local tree identical to this tip's tree (4a3c89357580c974b25418c7a38cf0e888d42fdf).Red first
Three tests added to
core/test/state-journal.test.js; the four #2056/#2065 start-up cases are untouched. On live main8626664dwith no source change, three runs:# tests 15 / # pass 13 / # fail 2each time:a journal folder swapped for a link after start-up records nothing and writes nothing outside the home (#2074)—warnings.lengthexpected 1, actual 0 (the folder that is a link now is refused when the write runs).a journal file swapped for a link after start-up is left byte-for-byte unchanged (#2074)— target actualPRIVATE LINE\n{"seq":2,…,"actor":"host"}\n, expectedPRIVATE LINE\n.a journal that is still its own folder and file keeps recording (#2074 control)passes.With the fix:
15/15/0three times. Mutation arm (both new guards removed):15/13/2three times, the same two failures.Verification at the tip
Tip SHA: 04867b6
Ran:
TZ=UTC ARCH_DOCS_BASE=8540c35c95e1a1125ad00c2ebc46655bd730a64a npm run verifyon a local tree identical to this tip's tree (4a3c89357580c974b25418c7a38cf0e888d42fdf) — core 2552, social 541, tree 127, timeline 135, workflow 336,.github/scripts572, interop 37, live-e2e 24 (4324 tests, 0 fail); core lint 73 warnings / 0 errors;arch-docs: OK (6 changed file(s));ok 10 patches apply cleanly in order;ok core/ equals ds-bot/ + patches/ds-bot/;ok patches/ds-bot/ is what generate writes (generate is a no-op);changelog: 49 fragment(s) … are well formed;node scripts/build-client.mjs --checkexit 0.node scripts/ds-bot-patches.mjs generatetwice, the second run leavesgit status --porcelainempty.Not run (and why): the smoke test —
core/dev/bench.shstarts a DSH web bench from adeepseek-harnesssource checkout (pnpm -s dsh), and this box has no such checkout (only the installed npm package), so the bench cannot start here; it is not part ofverifyor the requiredtests-ok.Checkpoint
{ "pr": 2078, "claim": "Dev-3", "issue": 2074, "summary": "The journal asked whether its folder was real only at start-up, so a folder or state.jsonl swapped for a link afterwards received a snapshot outside the home. The write now asks again: a swapped folder stops recording with one warning, and a swapped state.jsonl is never written through; a prune replaces the link with a fresh file in the verified folder. Three tests cover the swapped folder, the swapped file and a control, and the four earlier start-up cases are unchanged. A wording follow-up states that split after Security's FAIL at ed31d066.", "files": [ "core/src/host/journal.js", "core/test/state-journal.test.js", "patches/ds-bot/files/src/host/journal.js", "patches/ds-bot/files/test/state-journal.test.js", "docs/subsystems/core-host.md", "changelog.d/2074-journal-link-swap.fixed.md" ], "checks": { "ran": "TZ=UTC ARCH_DOCS_BASE=8540c35c95e1a1125ad00c2ebc46655bd730a64a npm run verify; node scripts/ds-bot-patches.mjs generate (twice); node .github/scripts/changelog.mjs check", "result": "green", "at": "04867b6638e9563e138be9f4b50e2555ba5ec8a6" }, "next": "none — ready for review" }