Harden the server and the app for production, and give Deckle a test suite - #26
Merged
Merged
Conversation
…suite Security: - Refuse any path that resolves into .deckle-state, not just one whose raw first segment matches; "./.deckle-state/assistant.json" read the API key. - Stop trusting X-Forwarded-For from anyone for login and token throttling. DECKLE_TRUST_PROXY opts in, counting hops from the right; the attempts table is capped. - Open files before writing headers and stream through pipeline, so an unreadable file is a 500 rather than a crashed process. - Derive the session signing key from the password too, compare passwords as digests, tolerate malformed cookies, require the app header to sign out. - Send a Content-Security-Policy with every response. - Render bookmark hrefs only for http(s) URLs; cap ZIP inflation at the size the archive claims; validate AI tool, memory and inbox paths in the app. - npm audit fix for linkify-it, postcss, nanoid and browserslist. Data loss: - Serialise note autosave flushes so an older batch can't land last. - Move tasks and bookmarks onto one useDataFile hook: no save before load, saves in order, pending changes written to their own library on switch. Unreadable data files are copied aside in the app and refused by the API. - Lock queue index updates so concurrent runs don't drop or revert rows. - API: roll recurring tasks forward on completion, validate a PATCH before moving the note, reject non-object bodies, real dates, hex colours; end an export whose client disconnected. Tests: 285 Vitest tests covering the server through its real handler (now built by server/app.mjs), /api/v1, every storage backend including the remote adapter against a live server, the queue, AI tools and the React hooks. CI runs them before the build. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Merged
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.
A full review of Deckle for production. It fixes six security issues and five ways data could be lost, and adds the project's first test suite, which CI now runs before the build.
Before deploying
Behind Caddy, Traefik or nginx, set
DECKLE_TRUST_PROXY=true, or a number for a chain of proxies. Login throttling no longer believesX-Forwarded-Forfrom anyone. Without the setting, every visitor behind a proxy shares one counter, so ten wrong passwords lock everyone out for 15 minutes. This is a new setting with a safe default, so the release is a minor bump (1.7.0) under the versioning policy.Security
./.deckle-state/assistant.jsongot past the reserved-folder check, which compared the raw first path segment. The check now runs on the resolved path, ignores letter case, and also covers a customDECKLE_STATE_DIRinside the library. It also put the key within reach of the assistant's read-onlyread_filetool.server/throttle.mjsnow takes the address from the connection unless a proxy is trusted, reads the header from the right-hand end, and caps how many addresses it tracks.pipeline.script-src 'self') on every response. It still allows calls to any AI provider, including LM Studio on the local network.hrefs are drawn only for http(s) URLs...and hidden folders, whatever the storage underneath allows.npm audit fixupdates linkify-it, postcss, nanoid and browserslist.Data loss
useDataFilehook..deckle/*.unreadable-*.json) before anything replaces it. The API refuses to write over one, with500 store_unreadable.PATCHis validated before the note is moved.Structure
The server's setup moved from
server/index.mjsinto a side-effect-freeserver/app.mjs, which the tests drive directly.index.mjsnow only boots it. The README,.env.example,compose.yaml, the OpenAPI document and the changelog are updated.Test plan
npm test: 285 tests in 20 files, covering:/api/v1useDataFile, anduseNotesautosave ordering)npm run buildjavascript:bookmark on disk. No CSP violations and no page errors.server/.Known and not addressed
There are 35 moderate npm advisories, all from Tiptap v2 (
mergeAttributesand__proto__). The fix exists only in Tiptap v3, a major editor migration that belongs in its own PR. Deckle never passes attribute objects that could reach that path, because content comes from Markdown through the DOM parser.🤖 Generated with Claude Code