Skip to content

feat: v0.3.1 Quick Wins - Atomic Transactions & Input Validation#23

Merged
dean0x merged 3 commits intomainfrom
feature/v0.3.1-quick-wins
Nov 18, 2025
Merged

feat: v0.3.1 Quick Wins - Atomic Transactions & Input Validation#23
dean0x merged 3 commits intomainfrom
feature/v0.3.1-quick-wins

Conversation

@dean0x
Copy link
Owner

@dean0x dean0x commented Nov 17, 2025

User description

Summary

Implements two security and data consistency improvements for the task dependency system:

Changes

🔄 Atomic Batch Operations

  • New addDependencies() method with all-or-nothing semantics
  • Transaction rollback on any validation failure (cycle, duplicate, not found)
  • DependencyHandler refactored to use atomic batch operations
  • Eliminates partial state when adding multiple dependencies

🔒 Security Hardening

  • Maximum 100 dependencies per task (prevents DoS)
  • Maximum 100 dependency chain depth (prevents stack overflow)
  • Clear error messages with current counts and limits
  • New getMaxDepth() algorithm using DFS with memoization

🧪 Test Coverage

  • 18 new comprehensive tests (+842 lines)
  • Atomic rollback behavior validation
  • Large batch operations (50+ dependencies)
  • Chain depth calculations
  • All 221 unit tests passing

Test plan

  • All unit tests pass (npm test - 221 tests)
  • Build succeeds (npm run build)
  • New validation limits enforced correctly
  • Atomic rollback works on failure
  • CHANGELOG.md updated

Files Changed

  • src/core/interfaces.ts - Added addDependencies() to interface
  • src/core/dependency-graph.ts - Added getMaxDepth() algorithm
  • src/implementations/dependency-repository.ts - Batch method + validation
  • src/services/handlers/dependency-handler.ts - Atomic batch operations
  • tests/unit/core/dependency-graph.test.ts - 7 new tests
  • tests/unit/implementations/dependency-repository.test.ts - 11 new tests
  • CHANGELOG.md - Documented v0.3.1 changes

Closes #11, Closes #12

🤖 Generated with Claude Code


PR Type

Enhancement, Tests


Description

  • Implements atomic batch dependency operations with all-or-nothing semantics

  • Adds input validation limits: max 100 dependencies per task, max 100 chain depth

  • New DependencyGraph.getMaxDepth() algorithm using DFS with memoization

  • Refactors DependencyHandler to use atomic batch operations for consistency

  • Adds 18 comprehensive tests covering rollback, validation, and edge cases


Diagram Walkthrough

flowchart LR
  A["New addDependencies<br/>Batch Method"] --> B["Atomic Transaction<br/>All-or-Nothing"]
  B --> C["Rollback on<br/>Validation Failure"]
  D["Input Validation<br/>Limits"] --> E["Max 100 Dependencies<br/>per Task"]
  D --> F["Max 100 Chain<br/>Depth"]
  G["getMaxDepth<br/>Algorithm"] --> H["DFS with<br/>Memoization"]
  A --> I["DependencyHandler<br/>Refactored"]
  E --> J["DoS Prevention"]
  F --> K["Stack Overflow<br/>Prevention"]
Loading

File Walkthrough

Relevant files
Enhancement
dependency-graph.ts
Add chain depth calculation algorithm                                       

src/core/dependency-graph.ts

  • Added getMaxDepth() method to calculate longest dependency chain from
    a task
  • Implements DFS algorithm with memoization for O(V+E) complexity
  • Handles cycle detection and diamond-shaped dependency graphs
  • Includes comprehensive JSDoc with examples
+73/-0   
interfaces.ts
Add batch dependency interface method                                       

src/core/interfaces.ts

  • Added addDependencies() method signature to DependencyRepository
    interface
  • Supports atomic batch operations with all-or-nothing semantics
  • Returns array of TaskDependency objects on success
+7/-0     
dependency-repository.ts
Implement atomic batch operations and validation limits   

src/implementations/dependency-repository.ts

  • Added security validation: max 100 dependencies per task in
    addDependency()
  • Added chain depth validation using getMaxDepth() to prevent stack
    overflow
  • Implemented new addDependencies() method with atomic transaction
    semantics
  • Uses better-sqlite3 .transaction() for true ACID compliance
  • Comprehensive validation before persisting: cycle detection,
    duplicates, task existence
  • Includes detailed error messages with current counts and limits
+199/-0 
dependency-handler.ts
Refactor to use atomic batch dependency operations             

src/services/handlers/dependency-handler.ts

  • Refactored handleTaskDelegated() to use atomic addDependencies()
    instead of loop
  • Simplified error handling with single batch operation
  • Maintains event emission for compatibility with existing listeners
  • Updated comments to reflect atomicity guarantees
+28/-56 
Tests
dependency-graph.test.ts
Add comprehensive chain depth calculation tests                   

tests/unit/core/dependency-graph.test.ts

  • Added 7 new tests for getMaxDepth() algorithm in new test suite
  • Tests cover: no dependencies, single dependency, linear chains,
    diamond graphs
  • Includes deep chain test (101 tasks) and memoization performance test
  • Validates correct depth calculation for complex dependency structures
+158/-0 
dependency-repository.test.ts
Add atomic batch and validation limit tests                           

tests/unit/implementations/dependency-repository.test.ts

  • Added 3 tests for max dependencies per task validation (100 limit)
  • Added 1 test for max chain depth validation (100 limit)
  • Added 11 tests for atomic batch operations: rollback on cycle,
    duplicate, not found
  • Tests verify atomicity: no partial state persisted on any failure
  • Includes large batch tests (50+ dependencies) and cache invalidation
    verification
+355/-0 
Documentation
CHANGELOG.md
Document v0.3.1 features and test coverage                             

CHANGELOG.md

  • Documented v0.3.1 security hardening: input validation limits (max 100
    deps, max 100 depth)
  • Documented atomic multi-dependency transactions with rollback
    semantics
  • Added chain depth calculation algorithm documentation
  • Documented 18 new tests and updated test count from 203 to 221
  • Organized changes by feature with emoji labels for clarity
+22/-0   

Implement two quick wins for v0.3.1 (Issues #11 and #12):

- Atomic multi-dependency transactions with all-or-nothing semantics
- Input validation: max 100 deps/task, max 100 chain depth
- New DependencyGraph.getMaxDepth() algorithm (DFS with memoization)
- DependencyHandler refactored to use batch operations
- 18 new comprehensive tests (221 total, was 203)

Closes #11, Closes #12

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@qodo-free-for-open-source-projects
Copy link

qodo-free-for-open-source-projects bot commented Nov 17, 2025

PR Compliance Guide 🔍

(Compliance updated until commit 0d8379b)

Below is a summary of compliance checks for this PR:

Security Compliance
Missing cycle detection

Description: The getMaxDepth() method lacks cycle detection, allowing infinite recursion if a cycle
exists in the graph despite the currentPath tracking that is never used to detect cycles.
dependency-graph.ts [383-415]

Referred Code
const calculateDepth = (node: string, currentPath: Set<string>): number => {
  // Return memoized result if available
  if (memo.has(node)) {
    return memo.get(node)!;
  }

  const deps = this.graph.get(node);

  // Leaf node has depth 0
  if (!deps || deps.size === 0) {
    memo.set(node, 0);
    return 0;
  }

  // Track current path for cycle detection
  currentPath.add(node);

  // Calculate max depth of all dependencies
  let maxDepth = 0;
  for (const dep of deps) {
    const depth = calculateDepth(dep, currentPath);


 ... (clipped 12 lines)
Duplicate dependency bypass

Description: The validation checks array length against MAX_DEPENDENCIES_PER_TASK but doesn't prevent a
single batch from containing duplicate task IDs, which could bypass the intended limit if
the same dependency is listed multiple times.
dependency-repository.ts [165-171]

Referred Code
// Limit to MAX_DEPENDENCIES_PER_TASK for reasonable production workflows
if (dependsOn.length > SQLiteDependencyRepository.MAX_DEPENDENCIES_PER_TASK) {
  return err(new ClaudineError(
    ErrorCode.INVALID_OPERATION,
    `Cannot add ${dependsOn.length} dependencies: task cannot have more than ${SQLiteDependencyRepository.MAX_DEPENDENCIES_PER_TASK} dependencies`
  ));
}
Ticket Compliance
🟡
🎫 #12
🟢 Add maximum limit of 100 dependencies per task to prevent DoS attacks
Add maximum limit of 100 dependency chain depth to prevent stack overflow
Return clear error messages with INVALID_OPERATION error code
Provide reasonable limits for production workflows
Prevent system instability from deep recursion
🔴 Implement validation in DependencyHandler.addDependency() method
Check current dependency count before adding new dependency
Check chain depth using transitive closure (getAllDependencies)
🟢
🎫 #11
🟢 Wrap multiple dependency additions in single atomic transaction
Prevent partial state when adding multiple dependencies fails mid-way
Implement addDependencies() method that accepts array of TaskIds
Use database transaction to ensure all succeed or all fail atomically
Provide rollback capability on failure
Ensure consistency for complex dependency chains
Better error handling with automatic rollback
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

Previous compliance checks

Compliance check up to commit d85f619
Security Compliance
🟢
No security concerns identified No security vulnerabilities detected by AI analysis. Human verification advised for critical code.
Ticket Compliance
🟢
🎫 #11
🟢 Wrap multiple dependency additions in single atomic transaction
Prevent partial state when adding multiple dependencies
All dependencies succeed or all fail atomically
Better error handling with rollback on failure
Ensures consistency for complex dependency chains
🟢
🎫 #12
🟢 Add max 100 dependencies per task limit to prevent DoS attacks
Add max 100 dependency chain depth to prevent stack overflow
Check current dependency count before adding
Check chain depth using transitive closure
Provide clear error messages for users hitting limits
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

@qodo-free-for-open-source-projects
Copy link

qodo-free-for-open-source-projects bot commented Nov 17, 2025

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Refactor to eliminate duplicate logic

Refactor the addDependency method to call the new addDependencies method with a
single dependency. This will remove duplicated validation logic and centralize
it within addDependencies.

Examples:

src/implementations/dependency-repository.ts [112-238]
  async addDependency(taskId: TaskId, dependsOnTaskId: TaskId): Promise<Result<TaskDependency>> {
    // SECURITY: TOCTOU Fix - Use synchronous .transaction() for true atomicity
    // Per Wikipedia TOCTOU principles: check and use must be atomic
    // better-sqlite3's .transaction() ensures no JavaScript event loop interleaving
    // Rationale: Async functions with BEGIN/COMMIT allow race conditions
    const addDependencyTransaction = this.db.transaction((taskId: TaskId, dependsOnTaskId: TaskId) => {
      // ALL operations below are synchronous - no await, no yielding to event loop
      // This guarantees atomicity: no other transaction can interleave

      // VALIDATION: Check both tasks exist (foreign key validation)

 ... (clipped 117 lines)
src/implementations/dependency-repository.ts [265-414]
  async addDependencies(taskId: TaskId, dependsOn: readonly TaskId[]): Promise<Result<readonly TaskDependency[]>> {
    // VALIDATION: Reject empty arrays
    if (dependsOn.length === 0) {
      return err(new ClaudineError(
        ErrorCode.INVALID_OPERATION,
        'Cannot add dependencies: empty array provided'
      ));
    }

    // SECURITY: Prevent DoS attacks with excessive dependencies

 ... (clipped 140 lines)

Solution Walkthrough:

Before:

class SQLiteDependencyRepository {
  async addDependency(taskId, dependsOnTaskId) {
    // ... transaction start
    // ... validation: task exists
    // ... validation: max deps
    // ... validation: dependency exists
    // ... validation: cycle check
    // ... validation: depth check
    // ... insert single dependency
    // ... transaction end
  }

  async addDependencies(taskId, dependsOn) {
    // ... transaction start
    // ... validation: task exists
    // ... validation: max deps
    // ... loop over dependsOn:
    //     ... validation: dependency exists
    //     ... validation: cycle check
    //     ... validation: depth check
    // ... loop over dependsOn to insert
    // ... transaction end
  }
}

After:

class SQLiteDependencyRepository {
  async addDependency(taskId, dependsOnTaskId) {
    const result = await this.addDependencies(taskId, [dependsOnTaskId]);
    if (result.ok) {
      return ok(result.value[0]);
    }
    return result;
  }

  async addDependencies(taskId, dependsOn) {
    // ... transaction start
    // ... validation: task exists
    // ... validation: max deps
    // ... loop over dependsOn:
    //     ... validation: dependency exists
    //     ... validation: cycle check
    //     ... validation: depth check
    // ... loop over dependsOn to insert
    // ... transaction end
  }
}
Suggestion importance[1-10]: 7

__

Why: The suggestion correctly identifies significant duplication of complex validation logic between addDependency and addDependencies, and the proposed refactoring would centralize this logic, improving maintainability.

Medium
  • Update

…ication

Addresses Qodo PR suggestion to centralize validation logic.
Reduces addDependency method from ~120 lines to 13 lines.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…formance

Fixes 6 issues identified in code review audit:

1. CRITICAL: Removed unused `visited` variable in getMaxDepth()
   - Dead code at src/core/dependency-graph.ts:378

2. HIGH: Removed redundant cycle detection in getMaxDepth()
   - Defensive check was unnecessary since callers validate
   - Lines 384-387 removed for cleaner code

3. HIGH: Extracted magic number 100 to named constants
   - Created MAX_DEPENDENCIES_PER_TASK = 100
   - Created MAX_DEPENDENCY_CHAIN_DEPTH = 100
   - Applied in 4 locations for better maintainability

4. BLOCKING: Fixed flaky performance test
   - Removed timing assertion that would fail in CI
   - Performance tests should be in separate benchmark suite

5. BLOCKING: Fixed Result pattern inconsistency
   - Changed getMaxDepth() return type from Result<number> to number
   - Method never errors, so Result wrapper was dead code
   - Updated all call sites and tests

6. HIGH: Optimized quadratic depth validation loop
   - Moved getMaxDepth() outside loop in addDependencies()
   - Reduced complexity from O(N * (V+E)) to O(V+E)
   - Calculate max depth once for all dependencies instead of per-dependency

All 221 tests passing.

Related: PR #23 code review findings

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@dean0x dean0x merged commit 83de98d into main Nov 18, 2025
2 checks passed
@dean0x dean0x deleted the feature/v0.3.1-quick-wins branch November 18, 2025 07:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[v0.3.1] Input Validation Limits for Dependency System [v0.3.1] Multi-Dependency Atomic Transactions

1 participant