Skip to content

Harden DynaRust: security, durability & performance fixes from service analysis#9

Merged
yourfavDev merged 1 commit into
mainfrom
claude/service-analysis-report-69u3ij
Jul 10, 2026
Merged

Harden DynaRust: security, durability & performance fixes from service analysis#9
yourfavDev merged 1 commit into
mainfrom
claude/service-analysis-report-69u3ij

Conversation

@yourfavDev

Copy link
Copy Markdown
Owner

This PR implements the fixes identified in the service analysis report (docs/SERVICE_ANALYSIS_REPORT.md, also included here). Everything compiles with zero warnings, passes clippy -D warnings, passes the new unit tests, and was verified end-to-end against a running node.

Security

  • Argon2id password hashing replaces the unstretched salted SHA-256. Legacy 64-hex records are detected and transparently re-hashed on the owner's next correct login.
  • Per-IP rate limiting on /auth (AUTH_RATE_LIMIT, default 30/min).
  • Closed the unauthenticated SSRF: /indirect_ping now requires the cluster token and only targets known members. /membership and /stats also require the token.
  • Removed the weak "default_secret" fallbacks in the cluster membership handlers.

Durability & correctness

  • Encrypted, synchronous per-table write-ahead log on every mutation, with version-aware replay on load and a final flush on graceful shutdown. (The WAL was previously advertised but never actually written.)
  • Delete tombstones that participate in conflict resolution and replicate through the versioned merge path, so a replica that missed a delete can no longer resurrect the key via read repair.
  • Corrupt snapshot/WAL chunks are skipped-and-logged instead of process::exit(1); expired tombstones are GC'd on load.

Performance & scalability

  • Version-stable FNV-1a consistent-hash ring (no more DefaultHasher cross-toolchain drift), cached and rebuilt only on membership change.
  • Configurable replication factor (REPLICATION_FACTOR, default 3) so reads/writes hit a replica subset instead of the whole cluster.
  • Replication permits are acquired inside the spawned task, so the request path no longer stalls on replication capacity.

Operability

  • Structured logging via env_logger honouring RUST_LOG.
  • Deduplicated the HTTP/HTTPS route tables into a single 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 actually works.

CI, tests & docs

  • Rewrote CI: generate the build-time key, add 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).
  • Added unit tests for the ring, tombstones, vector-clock dominance, and safe-name validation.
  • Fixed the Dockerfile to generate the key at build time (bumped builder to Rust 1.90).
  • Reconciled the README's consistency/durability/security claims and documented the new configuration variables.

Verification

  • cargo test — 9 passing; cargo clippy --all-targets -- -D warnings — clean.
  • Live single-node run confirmed: Argon2 register/login (wrong password → 401), PUT/GET, delete → tombstone → 404, WAL durability across an immediate kill/restart (no snapshot), tombstone survives restart, WAL encrypted at rest, /stats 401 without token / 200 with token, /indirect_ping 401 without token.

Notes

  • New config: REPLICATION_FACTOR, AUTH_RATE_LIMIT (both optional, see .env.example).
  • Behavior change: data now replicates to REPLICATION_FACTOR nodes (default 3) rather than the full cluster; auth records remain replicated cluster-wide for login-anywhere.
  • Out of scope: the Dependabot dependency advisories on the default branch (separate dependency-bump work).

🤖 Generated with Claude Code

https://claude.ai/code/session_01UPTaq37FEQzRMV1R87LaKv


Generated by Claude Code

…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:
@yourfavDev yourfavDev merged commit 7c9f78d into main Jul 10, 2026
6 checks passed
@yourfavDev yourfavDev deleted the claude/service-analysis-report-69u3ij branch July 10, 2026 17:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants