-
Notifications
You must be signed in to change notification settings - Fork 3
feat: pre-announcement hardening across kernel, adapters, lenses, CLI, and supply chain #43
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
bb1c665
feat(kernel): harden durability, safety, and API contracts
cevheri 8bd2e6e
feat(lens,cli,dst): namespace safety, validation guards, IO-fault DST…
cevheri 5f1e3d4
feat(ci,docs): supply-chain hardening and honest durability docs
cevheri 143b660
fix(kernel,adapter): close adversarial-review findings on the hardeni…
cevheri f333ff3
fix(kernel,adapter,lens): resolve Copilot review findings on PR #43
cevheri 6c21f52
fix(lens,adapter,ci): resolve second-round Copilot review findings
cevheri 544b257
test(dst): scale the seeded-loop timeout with LIBREDB_DST_SEEDS
cevheri 67d89de
fix(lens,kernel,cli): close Codex review findings on read-path valida…
cevheri c6b72c3
chore(cli,test,ci): apply Kimi review nits and add a binary smoke to CI
cevheri 567240c
docs(kernel): state getRange snapshot cost precisely
cevheri 24177ac
fix(cli,browser,docs): close GPT review findings on import validation…
cevheri aa5f37f
test(adapter): cover the reclaim race window deterministically
cevheri 81fa941
test(kernel,dst): aim the mid-log corruption tests at actual payload …
cevheri 243f317
docs: remove the distribution channels design document
cevheri 13544d3
docs: sync every document with the hardened code
cevheri a0978c3
fix(adapter,dst): narrow directory-fsync error handling; document the…
cevheri File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| --- | ||
| "@libredb/libredb": minor | ||
| --- | ||
|
|
||
| Durability, safety, and API-contract hardening across the kernel, adapters, lenses, and CLI (the pre-announcement audit wave). | ||
|
|
||
| On-disk format: new databases now begin with an 8-byte `LRDB` magic/version header, and each record header carries a checksum of its own length field. Files written by earlier releases (headerless) keep opening through a legacy read path, and keep their legacy record framing on later appends. The header is what lets `open()` refuse a file that is not a LibreDB database with a clear error instead of destroying it; the record-header checksum is what lets recovery refuse a damaged length field instead of mistaking it for a torn tail. | ||
|
|
||
| DOWNGRADE WARNING: a file written by this release must never be opened by 0.1.3 or older — the old recovery cannot parse the header, classifies the whole file as a torn tail, and silently truncates it to zero bytes. Back up before any downgrade. Three smaller legacy-behavior changes: a headerless file whose only record is torn/incomplete now refuses to open as `NOT_A_DATABASE` (0.1.3 recovered it to an empty database; refusing is the safe reading, since such a file is indistinguishable from a foreign one); any file shorter than the 8-byte header is likewise refused untouched (a crash inside the first bytes of a brand-new database's first-ever commit therefore needs a manual delete — nothing in it was acknowledged); and a legacy length-field corruption still reads as a torn tail (the legacy format has no header checksum — the v1 format exists to close exactly that gap). | ||
|
|
||
| Kernel: | ||
|
|
||
| - `open({ path })` on a non-LibreDB file throws `NOT_A_DATABASE` and leaves the file byte-for-byte untouched (previously the file was silently truncated to zero). | ||
| - Recovery classifies failures: a torn tail truncates (reported through the new `onRecovery` open option), while mid-log corruption throws `CORRUPT_WAL` and truncates nothing. Record payloads are structurally validated during replay. | ||
| - A failed append/fsync latches the database: every later `transact()` throws `FAILED` until reopen, so an IO error can never lead recovery to silently drop later acknowledged commits. | ||
| - `transact()` rejects async callbacks (`ASYNC_TRANSACTION`): writes after an `await` could never reach the log. | ||
| - Keys and values are copied at the transaction boundary in both directions — caller buffer reuse and mutation of returned buffers can no longer corrupt the store. | ||
| - `getRange` snapshots at first iteration, so delete-while-scanning visits every entry exactly once. | ||
| - `close()` inside a transaction throws `CLOSE_IN_TRANSACTION` instead of surfacing a raw file error. | ||
| - `open()` takes an exclusive per-file lock (`<path>.lock`, pid/host/nonce): a second writer throws `LOCKED` instead of silently diverging; locks from verifiably dead holders are reclaimed automatically. `FileSystem` gains an optional `lock()` seam method. | ||
| - All kernel failures are now `LibreDbError` instances carrying a stable `code` (exported, with the `ErrorCode` and `RecoveryInfo` types). | ||
|
|
||
| Adapters: | ||
|
|
||
| - node-fs: creating a database fsyncs the parent directory (a fresh database can no longer vanish wholesale on power loss); a directory-fsync failure that is not a platform limitation (e.g. EIO) now surfaces as an error instead of being silently ignored; recovery truncation is fsync'd; reads are positional on the WAL's own file descriptor instead of re-reading the whole file per call. | ||
| - OPFS: reads loop until filled, so a legal short read can no longer masquerade as a torn tail; recovery treats an incomplete read as an IO fault (`INCOMPLETE_READ`), never as license to truncate. | ||
|
|
||
| Lenses: | ||
|
|
||
| - Collection/table names may not be empty or contain `:` (both broke namespace isolation); ids keep full freedom. | ||
| - Strings that are not well-formed UTF-16 (lone surrogates) are rejected wherever they would become keys, ids, names, or kv values — distinct strings can no longer silently collide on one key. | ||
| - Relational `number` columns reject `NaN` and the infinities (JSON would store them as `null`). | ||
| - `doc()` refuses a name cataloged as a relational table (it would bypass schema validation); `table()` refuses a document collection's name. | ||
| - `find()`/`where()` reject a predicate field explicitly set to `undefined`, which previously matched documents *missing* the field. | ||
|
|
||
| CLI: | ||
|
|
||
| - Write commands rely on the kernel's exclusive lock; `--force` removes a lock only when its holder is not verifiably alive, and never deletes a file that is not a libredb lock. Automatic reclaim is stricter still: only a lock whose holder is VERIFIABLY dead (same host, pid gone) is reclaimed without `--force` — anonymous locks (empty, or the sentinel-only 0.1.x format) carry no liveness information and now require `--force`. | ||
| - `get`/`scan` escape control characters (including tab and newline) by default so untrusted values cannot inject terminal escape sequences — scripts that consumed values verbatim should pass `--raw`. | ||
|
|
||
| New exports: `LibreDbError`, `ErrorCode`, `RecoveryInfo`, `nodeFileSystem`, and `readonlyFileSystem` (open a database for inspection with no lock and no writes — the supported way to read a file a live writer holds). | ||
|
|
||
| Docker image now runs as a non-root user (distroless `:nonroot`, uid 65532): bind-mounted directories must be writable by that uid, or pass `--user "$(id -u):$(id -g)"`. |
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| # Dependabot keeps the SHA-pinned actions, the digest-pinned Docker bases, and | ||
| # the npm devDependencies from going stale: pinning without an update loop | ||
| # inverts over time (CVE fixes never arrive unless someone remembers to bump | ||
| # digests by hand). Weekly PRs preserve the pinning discipline — every bump is | ||
| # still a reviewed, pinned change. | ||
| version: 2 | ||
| updates: | ||
| - package-ecosystem: "github-actions" | ||
| directory: "/" | ||
| schedule: | ||
| interval: "weekly" | ||
| - package-ecosystem: "docker" | ||
| directory: "/" | ||
| schedule: | ||
| interval: "weekly" | ||
| - package-ecosystem: "npm" | ||
| directory: "/" | ||
| schedule: | ||
| interval: "weekly" | ||
| # Zero runtime dependencies is a design fact (license tripwire enforces | ||
| # it), so everything here is devDependencies; group the noise. | ||
| groups: | ||
| dev-dependencies: | ||
| patterns: | ||
| - "*" |
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
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
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
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
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.