Repository navigation
basou: Refuse a session's events.jsonl or session.yaml that is not a regular file, instead of following it - #357
Merged
Conversation
…regular file, instead of following it A session's events.jsonl and session.yaml were read through whatever stood at their names: a symlink was followed to a file outside the store, and a FIFO made basou verify, basou board measure and every reader of the session's events wait without end. basou never creates either form. A shared reader in session-dir.ts now lstats the file first. A symlink, whatever it points to, or anything but a regular file (a directory, a FIFO) is refused with SessionFileNotAFileError, which carries the session id, the file and the kind, before anything is read; an absent file is handled as before. replayEvents / readAllEvents, readSessionYaml and the listing, verifyEventsChain, the chained append (and so every note, decision record, task attach, approval resolution and exec / run append and finalize), the in-place re-import, rechain, session show, the running transition of exec and run, and the board's count of lost lines all go through it. - basou verify reports such a session tampered with a new reason, events_not_a_file or yaml_not_a_file (events.jsonl first), and event_count 0. session rechain skips it with the same reason and exits non-zero; an in-place re-import skips it as a broken prior. - Listings leave out a session whose session.yaml is such, as session_yaml_not_a_file, named by its full id; one whose events.jsonl is such is kept with its events unreadable. import warns that such a session may be imported again, and task refresh-linkage keeps a link to it. approval approve and reject stop for such a session.yaml instead of going on as for an unreadable one. - basou view's session page answers 404 for such a session.yaml. - The SDK treats such a file as a session entry that is not a directory: listSessions / getSession leave the session out, readEvents / streamEvents return no events, and each reports it to onDiagnostic. - basou board measure raises the method of integrity, trail, review_gaps, freshness and effort to 2, as each counts such a session differently. docs/spec/schemas.md lists the two reasons; docs/spec/workspace.md says what each command does with such a file. A directory at events.jsonl, which tests used to provoke a read failure, is now one of these cases, so those tests make the failure with chmod instead.
… is refused, and correct what the docs say Apply the review findings on the previous commit. - verify read neither file when events.jsonl was not a regular file, so a session a newer basou wrote was tampered instead of unsupported, and session_yaml_invalid went missing. A session.yaml that is a regular file is now read beside such a log, so its version decides as for any other row; only a session.yaml that is not a regular file leaves the row to the layout alone. - The SDK reports a refused events.jsonl as events_jsonl_unreadable, the words stats() and the renderers use for the same log. - docs/spec/compatibility.md bounds a command coming to refuse a layout basou never creates, the one way an invocation moves from 0 to a non-zero exit within 1.x: nothing changes on a layout basou creates, the refusal names what it refuses, and the changelog lists it. - The spec defines each new verify reason by its own file and leaves open which is given when both files are refused; it says which board sections read which file, what the SDK does, and that a federated mirror's sessions are covered too. The CHANGELOG no longer says the SDK treats such a file as a session entry that is not a directory, nor that the reason addition alone is what compatibility.md allows. - Tests cover run's running transition, a FIFO in exec's, each rechain reason failing the run on its own, and the board's count of lost lines.
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.
What
A session's
events.jsonlandsession.yaml(inside.basou/sessions/<id>/) were read through whatever stood at their names. A symlink was followed to a file outside the store, and a FIFO madebasou verify,basou board measureand every reader of the session's events wait without end. basou never creates either form.A shared reader in
packages/core/src/storage/session-dir.tsnow lstats the file first. A symlink, whatever it points to, or anything but a regular file (a directory, a FIFO) is refused withSessionFileNotAFileError(session id, file, kind) before anything is read; an absent file is handled as before. Every reader of the two files goes through it:replayEvents/readAllEvents,readSessionYamland the session listing,verifyEventsChain, the chained append (so every note, decision record, task attach, approval resolution, andexec/runappend and finalize), the in-place re-import,session rechain,session show, the running transition ofexecandrun, and the board's count of lost lines.This is the second part of the reader checks; the first (the session's entry itself) was #356.
Behaviour
basou verifyreports such a sessiontamperedwith a newreason,events_not_a_fileoryaml_not_a_file, andevent_count0; it used to follow the file (an intact log behind a symlink wasverified, exit0) or wait on a FIFO. Asession.yamlthat is a regular file is still read beside anevents.jsonlthat is not, so a newer basou's session staysunsupportedandsession_yaml_invalidis still reported.session rechainskips such a session with the same reasons and exits non-zero; an in-place re-import skips it as a broken prior.<file> of session <id> is not a regular file; a symlink or anything else there is not followed.approval approve/rejectstop for such asession.yaml(they used to go on for an unreadable one) and leave the approval pending.session.yamlis such (session_yaml_not_a_file, full id); one whoseevents.jsonlis such is kept, its events unreadable (events_jsonl_unreadable).importwarns that such a session may be imported again;task refresh-linkagekeeps a link to it.basou view:404for such asession.yaml; the session without its events for such anevents.jsonl.@basou/sdk:listSessions/getSessionleave out a session whosesession.yamlis such;readEvents/streamEventsreturn no events for such anevents.jsonland report it toonDiagnosticasevents_jsonl_unreadable, the wordsstats()and the renderers use (compatibility.md, "The errors may grow" item 4).basou board measure:integritycounts the session as verify judges it;trail,review_gapsandeffortare not measured for a refusedevents.jsonl, andreview_gaps,freshnessandeffortfor a refusedsession.yaml. The five sections' method versions go from 1 to 2.events.jsonl, which some tests used to provoke a read failure, is now one of these cases (verifyreportstamperedinstead of stopping); those tests make the failure withchmodinstead.Docs
docs/spec/schemas.mdsection 7.5 lists the two reasons, each defined by its own file (which one is given when both apply is left open), and whensession_yaml_invalidis left out.docs/spec/workspace.mdgains "A session's files are not followed", federated mirrors included.docs/spec/compatibility.mdgains "A layout basou never creates may come to be refused": the one way an invocation moves from0to a non-zero exit within1.x, bounded by nothing changing on a layout basou creates, the refusal naming what it refuses, and the changelog listing it. This PR is such a change, as thesymlink/not_a_directoryreasons were.Review
The second commit applies the findings of a convergent review and an unrequested divergent review (trigger: a published contract, the
verify --jsonreason values and the SDK's reads), each review-only, one round, with per-finding approval: the version gate running after the layout check,session_yaml_invalidon those rows, the SDK diagnostic wording, documentation that overstated the board and the SDK, the compatibility bound, and four test gaps. Not adopted: counting the log onyaml_not_a_filerows (kept consistent with the other layout rows), and renaming the reasons (settled before the work).Verification
pnpm -r build,pnpm -r typecheck,pnpm lintandpnpm -r testpass (core 2788, sdk 67, cli 1555).session.yaml), rechain, re-import, the appends and finalize, listings, board, view, approval, import, task linkage,exec/runand the SDK.mainblocks inbasou verify --jsonon a FIFOsession.yaml(killed by a 15 s alarm); this branch prints the twotamperedrows and exits 1.readFile, which only a swap between the verify gate and that read can reach.