Harden DynaRust: security, durability & performance fixes from service analysis#9
Merged
Merged
Conversation
…ysis Security - Replace unstretched salted SHA-256 password hashing with Argon2id; legacy records are transparently upgraded on next successful login. - Add per-IP fixed-window rate limiting to /auth (AUTH_RATE_LIMIT). - Gate /indirect_ping, /membership, and /stats behind the cluster token, and restrict indirect-ping targets to known members (closes SSRF). - Drop weak "default_secret" fallbacks in cluster membership handlers. Durability & correctness - Implement an encrypted, synchronous per-table write-ahead log on every mutation; version-aware replay on load; final flush on graceful shutdown. - Introduce delete tombstones that participate in conflict resolution so a replica that missed a delete cannot resurrect the key via read repair. - Skip-and-log corrupt snapshot/WAL chunks instead of process::exit, and GC expired tombstones on load. Performance & scalability - Version-stable FNV-1a consistent-hash ring (no more DefaultHasher drift), cached and rebuilt only on membership change. - Configurable replication factor (REPLICATION_FACTOR, default 3) so reads and writes hit a replica subset instead of the whole cluster. - Acquire replication permits inside the spawned task so the request path no longer blocks on replication capacity. Operability - Structured logging via env_logger honouring RUST_LOG. - Deduplicate the HTTP/HTTPS route tables into one configure_app. - Graceful shutdown flushes a final cold save. - Server-auth TLS (no mandatory client cert) plus CA trust for the internal client so HTTPS clustering works. CI, tests & docs - Rewrite CI: generate the build-time key, add clippy -D warnings + tests as gates, and release only after tests pass. - Add unit tests for the ring, tombstones, vector-clock dominance, and safe names. - Fix the Dockerfile to generate the key at build time (bump to Rust 1.90). - Reconcile README consistency/durability/security claims and document the new configuration variables. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UPTaq37FEQzRMV1R87LaKv
Comment on lines
+21
to
+62
| name: Build, lint & test | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: write | ||
|
|
||
| steps: | ||
| # 1. Checkout the repository code. | ||
| - name: Checkout Code | ||
| uses: actions/checkout@v4 | ||
|
|
||
| # 2. Cache Cargo Registry. | ||
| - name: Cache Cargo Registry | ||
| uses: actions/cache@v3 | ||
| - name: Install Rust toolchain | ||
| uses: dtolnay/rust-toolchain@stable | ||
| with: | ||
| path: ~/.cargo/registry | ||
| key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }} | ||
| restore-keys: | | ||
| ${{ runner.os }}-cargo-registry- | ||
| components: clippy, rustfmt | ||
|
|
||
| # 3. Cache Cargo Git Repositories. | ||
| - name: Cache Cargo Git Repositories | ||
| uses: actions/cache@v3 | ||
| - name: Cache cargo | ||
| uses: actions/cache@v4 | ||
| with: | ||
| path: ~/.cargo/git | ||
| key: ${{ runner.os }}-cargo-git-${{ hashFiles('**/Cargo.lock') }} | ||
| path: | | ||
| ~/.cargo/registry | ||
| ~/.cargo/git | ||
| target | ||
| key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} | ||
| restore-keys: | | ||
| ${{ runner.os }}-cargo-git- | ||
| ${{ runner.os }}-cargo- | ||
|
|
||
| # The AES-256 key is embedded at compile time via include_bytes!, so it | ||
| # must exist before any cargo invocation. It is intentionally gitignored; | ||
| # generate an ephemeral one for CI. | ||
| - name: Generate build-time encryption key | ||
| run: bash encryption.sh | ||
|
|
||
| # 4. Cache Build Artifacts (the target directory). | ||
| - name: Cache Build Output | ||
| uses: actions/cache@v3 | ||
| - name: Format check | ||
| run: cargo fmt --all --check | ||
| continue-on-error: true | ||
|
|
||
| - name: Clippy | ||
| run: cargo clippy --all-targets -- -D warnings | ||
|
|
||
| - name: Test | ||
| run: cargo test --locked | ||
|
|
||
| - name: Build (release) | ||
| run: cargo build --release --locked | ||
|
|
||
| release: |
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.
This PR implements the fixes identified in the service analysis report (
docs/SERVICE_ANALYSIS_REPORT.md, also included here). Everything compiles with zero warnings, passesclippy -D warnings, passes the new unit tests, and was verified end-to-end against a running node.Security
/auth(AUTH_RATE_LIMIT, default 30/min)./indirect_pingnow requires the cluster token and only targets known members./membershipand/statsalso require the token."default_secret"fallbacks in the cluster membership handlers.Durability & correctness
process::exit(1); expired tombstones are GC'd on load.Performance & scalability
DefaultHashercross-toolchain drift), cached and rebuilt only on membership change.REPLICATION_FACTOR, default 3) so reads/writes hit a replica subset instead of the whole cluster.Operability
env_loggerhonouringRUST_LOG.configure_app.CI, tests & docs
clippy -D warnings+ tests as gates, and release only after tests pass (previously the release build could not succeed because the compile-time key was never generated).Verification
cargo test— 9 passing;cargo clippy --all-targets -- -D warnings— clean./stats401 without token / 200 with token,/indirect_ping401 without token.Notes
REPLICATION_FACTOR,AUTH_RATE_LIMIT(both optional, see.env.example).REPLICATION_FACTORnodes (default 3) rather than the full cluster; auth records remain replicated cluster-wide for login-anywhere.🤖 Generated with Claude Code
https://claude.ai/code/session_01UPTaq37FEQzRMV1R87LaKv
Generated by Claude Code