Skip to content

feat: resolve 10 implementable tech debt TODOs#1

Merged
CybotTM merged 16 commits into
mainfrom
feat/tech-debt-cleanup
Feb 23, 2026
Merged

feat: resolve 10 implementable tech debt TODOs#1
CybotTM merged 16 commits into
mainfrom
feat/tech-debt-cleanup

Conversation

@CybotTM
Copy link
Copy Markdown
Owner

@CybotTM CybotTM commented Feb 23, 2026

Summary

Implements all 10 actionable tech debt items identified across 7 security review cycles, plus clarifies 7 deferred TODO comments with rationale.

Server (S1-S7) — 456 tests passing (+24 new)

  • S1 Snapshot download endpoint (GET /buckets/{id}/snapshots/{snapshotId}/download) with path traversal protection and SHA-256 integrity header
  • S2 Crash atomicity for snapshot uploads (write-to-temp + rename pattern, orphan .tmp cleanup)
  • S3 Device registration IP rate limit (5/IP/hour, follows WebSocket limiter pattern)
  • S4 WebSocket query param auth (?token= for immediate auth, backward-compatible with in-band)
  • S5 Bucket creator role transfer (PATCH /buckets/{id}/creator)
  • S6 Remove Sessions.signingKey redundancy (join to Devices table for authoritative key)
  • S7 Op table pruning after checkpoint acknowledgment (new CheckpointAcknowledgments table, periodic cleanup)

Android (A1-A3)

  • A1 QR codes now use signing key fingerprint instead of encryption key (SC-03)
  • A2 Snapshot hash covers calendar events + info bank entries (SEC6-A-16)
  • A3 OkHttp TokenAuthenticator for automatic 401 re-authentication with synchronized concurrent handling (SEC3-A-21)

Deferred TODOs

  • 7 remaining TODOs converted to DEFERRED(...) prefix with clear rationale for why each requires protocol/framework changes

Test plan

  • Server: 456 tests passing (Docker Gradle, +24 new tests)
  • Conformance: all vectors pass
  • Android: 881+ unit tests (CI verification — no local SDK)
  • Detekt: no new violations (CI verification)

Add GET /buckets/{id}/snapshots/{snapshotId}/download to stream
snapshot binary data with path traversal protection and SHA-256
response header. Includes tests for content match, wrong bucket (403),
non-existent snapshot (404), and unauthorized access.
Write snapshot to .tmp file first, rename to final name only after DB
commit succeeds. On failure, temp file is deleted. Add periodic cleanup
of orphan .tmp files older than 1 hour in both snapshot and blob
storage directories.
Add IP-based rate limiter allowing 5 registrations per IP per hour for
the POST /register endpoint. Returns 429 when limit exceeded. Follows
the same ConcurrentHashMap/IpWindow pattern used for WebSocket rate
limiting.
Support ?token=... query parameter for WebSocket authentication in
addition to in-band auth messages. Query param auth rejects invalid
tokens immediately with close code 4001. Absent query param falls
through to existing in-band auth for backward compatibility.
Add PATCH /buckets/{id}/creator endpoint to transfer bucket ownership
to another device with active access. Validates caller is current
creator, target has non-revoked access. Tests cover successful
transfer, unauthorized attempts, revoked targets, and post-transfer
permission enforcement.
Session validation now joins Sessions with Devices table to read the
current signing key, eliminating the redundant signingKey column in
Sessions. createSession writes empty string to the column (retained
for schema compatibility). This ensures sessions always return the
device's current key, avoiding stale key issues after rotation.
Add CheckpointAcknowledgments table for per-device checkpoint tracking.
Add POST /buckets/{id}/checkpoints/acknowledge endpoint. Implement
pruneAcknowledgedOps() that deletes ops covered by checkpoints where
all active devices have acknowledged, preserving the latest checkpoint's
ops as safety margin. Pruning runs in the periodic cleanup loop.
- Add ktor-client-websockets test dependency for WebSocket integration tests
- Reset DeviceRegistrationRateLimiter on module init for test isolation
- Use proper imports instead of FQN in pruneAllBuckets
- Fix WebSocket auth test to not depend on encodeDefaults=false type field
- Fix deprecated readBytes -> readRawBytes in SnapshotDownloadTest
Switch QR invite generation and verification to use the device's
signing key fingerprint instead of the encryption key fingerprint,
aligning with the pairing spec. Both generateInvite() and
continueJoinBucket() now consistently use signingKey for
fingerprint computation.
…(SEC6-A-16)

Add CalendarEventDao and InfoBankDao to SnapshotUseCase and include
their entities in computeStateHash(). Calendar events are sorted by
eventId; info bank entries are sorted by entryId and filtered to
non-deleted via the DAO query. This ensures state divergence in
these entity types is detected by snapshot comparison.
…on (SEC3-A-21)

Implement an OkHttp Authenticator that transparently handles 401
responses by re-authenticating via Ed25519 challenge-response and
retrying the failed request. Features: infinite loop prevention via
X-Auth-Retry header, synchronized concurrent 401 handling so only
one re-auth occurs, and dagger.Lazy<AuthRepository> to break the
circular Hilt dependency chain.
Update 7 remaining TODO/SEC comments to use DEFERRED prefix and explain
why each item requires protocol or framework changes before implementation.
Copy link
Copy Markdown

@github-advanced-security github-advanced-security AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

detekt found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request implements 10 actionable tech debt items identified across 7 security review cycles, plus clarifies 7 deferred TODOs with rationale. The changes span both server (Kotlin/Ktor) and Android (Kotlin) codebases, addressing security, reliability, and operational concerns.

Changes:

  • Server: 7 implementations including snapshot download endpoint, crash atomicity for uploads, IP rate limiting, WebSocket query param auth, creator role transfer, Sessions table redundancy removal, and op table pruning
  • Android: 3 implementations covering QR code signing key fingerprints, snapshot hash entity coverage, and automatic 401 re-authentication
  • Documentation: 7 deferred TODOs converted to DEFERRED(...) format with clear rationale

Reviewed changes

Copilot reviewed 29 out of 29 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
server/src/main/kotlin/dev/kidsync/server/routes/SyncRoutes.kt Implements snapshot download endpoint with path traversal protection, WebSocket query param auth, and crash-atomic snapshot uploads using temp files
server/src/main/kotlin/dev/kidsync/server/routes/DeviceRoutes.kt Adds IP-based rate limiter (5 registrations/IP/hour) for device registration
server/src/main/kotlin/dev/kidsync/server/routes/BucketRoutes.kt Adds PATCH /buckets/{id}/creator endpoint for creator role transfer
server/src/main/kotlin/dev/kidsync/server/services/SyncService.kt Implements op table pruning after checkpoint acknowledgment with safety margin
server/src/main/kotlin/dev/kidsync/server/services/BucketService.kt Adds transferCreator method with validation
server/src/main/kotlin/dev/kidsync/server/util/SessionUtil.kt Removes Sessions.signingKey redundancy by joining with Devices table
server/src/main/kotlin/dev/kidsync/server/db/Tables.kt Adds CheckpointAcknowledgments table for tracking per-device checkpoint acknowledgments
server/src/main/kotlin/dev/kidsync/server/Application.kt Adds periodic cleanup for .tmp files and op pruning, documents XForwardedHeaders limitation
android/app/src/main/java/com/kidsync/app/ui/viewmodel/BucketViewModel.kt Updates QR code generation and verification to use signing key fingerprint instead of encryption key
android/app/src/main/java/com/kidsync/app/domain/usecase/sync/SnapshotUseCase.kt Adds CalendarEvent and InfoBankEntry entities to snapshot hash computation
android/app/src/main/java/com/kidsync/app/data/remote/interceptor/TokenAuthenticator.kt Implements OkHttp Authenticator for automatic 401 re-authentication with synchronized concurrent handling
server/src/test/kotlin/dev/kidsync/server/*.kt Adds 24 new test cases covering all server implementations
android/app/src/test/java/com/kidsync/app/*.kt Adds/updates tests for Android changes with comprehensive coverage

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread server/src/main/kotlin/dev/kidsync/server/routes/DeviceRoutes.kt
Comment thread server/src/main/kotlin/dev/kidsync/server/routes/SyncRoutes.kt Outdated
Comment thread server/src/main/kotlin/dev/kidsync/server/routes/SyncRoutes.kt
- Replace raw HTTP status code literals with HttpStatusCode.*.value
- Add named constants for WebSocket close codes (4000/4001/4003)
- Replace wildcard imports with explicit imports in test files
- Remove unused uploadOpsAndGetCheckpoints function from OpPruningTest
- Fix unused targetAccess variable in BucketService (use .any() instead)
- Add @Suppress("ThrowsCount") to transferCreator()
- Fix BucketViewModelTest: use `returns Result.success(Unit)` instead
  of `just Runs` for uploadKeyAttestation() which returns Result<Unit>
- Declare WebSocket close code constants as Short (CloseReason ctor
  requires Short, not Int)
- Use api.kidsync.app in BucketViewModelTest URLs so the host check
  doesn't trigger android.util.Log.w which throws in unit tests
- WebSocketQueryParamAuthTest.kt: expand 4 wildcard imports
- TokenAuthenticatorTest.kt: expand io.mockk.* wildcard
- BucketViewModelTest.kt: expand io.mockk.* wildcard
- SnapshotUseCase: include childId and title in InfoBankEntry hash
  computation (missing fields could cause hash collisions)
- Snapshot download: use stored SHA-256 from DB instead of reading
  entire file into memory to recompute it
- Snapshot download: add .tmp file recovery for crash between DB
  commit and rename (complements existing periodic .tmp cleanup)
@CybotTM CybotTM merged commit 2dedc61 into main Feb 23, 2026
4 checks passed
@CybotTM CybotTM deleted the feat/tech-debt-cleanup branch February 23, 2026 12:56
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