Files
wanderbooks/crates/ledger-store/Cargo.toml
T
swaitsandClaude Fable 5.1 5f5dd8f7da feat(store): the data root under LOCALAPPDATA with an owner-only DACL, one lock seam, MoveFileEx (P11c)
Windows step 1 and 2 of D-62. Where Unix keeps the books' private folder
at mode 0700 and refuses one others can open, Windows now makes the same
promise with a DACL: `winsec::set_owner_only` gives the folder (and,
inherited, everything made in it) one protected allow entry for this
account's SID; `winsec::is_private` reads the effective DACL and owner
back and answers false for anything else (a missing DACL, an entry for
Everyone), so `Root::open` refuses a loosened root and `Root::setup`
makes it private again, exactly as the 0700 checks do. Every question the
system cannot answer is "not private". The root itself comes from the
shell's known folders (`SHGetKnownFolderPath`: the profile, and
LocalAppData wherever it was redirected), never from environment
variables the process that started us chose.

`rename_new` (the move that must never go over what is there, renameat2
RENAME_NOREPLACE on Linux) is `MoveFileExW` without the replace flag on
Windows, written through.

File locking sat behind `libc::flock` in ops.rs alone (the rest already
used std's File::try_lock, which is LockFileEx on Windows). It now goes
through `lock.rs`, which uses only std, so there is no second unsafe copy
of either call.

New dependency: windows-sys 0.61 behind cfg(windows), the raw bindings
only (no runtime), already in the lockfile through other crates; the
smallest Microsoft crate that covers SIDs, DACLs, the known-folder API,
pipe process ids and MoveFileExW. mise.toml adds the Windows target to
the pinned toolchain so `cargo check --target x86_64-pc-windows-msvc`
type-checks this arm on Linux.

CHOICE (P11c): nothing above the root is checked on Windows (the Unix
rule about folders above it being swappable has no Windows authority; the
profile's folders belong to the account and the Administrators).

Tests: tests/windows_root.rs (Windows job only), the cross-platform
`a_viewer_s_presence_is_a_shared_lock_others_can_see` in ops.rs.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HS8WZziDnyxunC23MUxrLp
2026-10-29 14:38:29 -06:00

62 lines
1.7 KiB
TOML

[package]
name = "ledger-store"
version = "0.1.0"
edition.workspace = true
license.workspace = true
repository.workspace = true
description = "Durable persistence for wanderbooks: a hash-chained JSONL journal as the source of truth, content-addressed blob store, and a disposable SQLite projection."
[dependencies]
ledger-core = { path = "../ledger-core" }
# The one reader (plan P6 step 1, D-53, D-61: its own crate): the writer journals a file's
# text at attach time and on `wanderbooks books extract`, so the extractor
# must be callable here rather than only from the server. It is pure and
# deterministic (no I/O, no network, no time source).
ledger-reader = { path = "../ledger-reader" }
rusqlite = { version = "0.32", features = ["bundled"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
chrono = "0.4"
rust_decimal = "1"
thiserror = "2"
sha2 = "0.10"
hex = "0.4"
getrandom = { version = "0.2", features = ["std"] }
subtle = "2"
argon2 = "0.6"
[target.'cfg(unix)'.dependencies]
libc = "0.2"
# Owner-only DACLs, the account's SID, the known-folder API and
# MoveFileExW (P11c, D-62). The raw bindings, no runtime: the smallest
# Microsoft crate that covers them, already in the lockfile.
[target.'cfg(windows)'.dependencies]
windows-sys = { version = "0.61", features = [
"Win32_Foundation",
"Win32_Security",
"Win32_Security_Authorization",
"Win32_Storage_FileSystem",
"Win32_System_Com",
"Win32_System_Pipes",
"Win32_System_SystemServices",
"Win32_System_Threading",
"Win32_UI_Shell",
] }
[dev-dependencies]
tempfile = "3"
proptest = "1"
rust_decimal = "1"
criterion = "0.8.2"
[target.'cfg(unix)'.dev-dependencies]
libc = "0.2"
[[bench]]
name = "store"
harness = false
[lints]
workspace = true