Skip to content

feat: Add Debug Mode for Hook and Tool Troubleshooting#5

Merged
maximelb merged 1 commit intomasterfrom
feat/debug-mode-payload-logging
Feb 4, 2026
Merged

feat: Add Debug Mode for Hook and Tool Troubleshooting#5
maximelb merged 1 commit intomasterfrom
feat/debug-mode-payload-logging

Conversation

@tomaz-lc
Copy link
Copy Markdown
Contributor

@tomaz-lc tomaz-lc commented Feb 3, 2026

Description

This PR adds a debug mode that logs detailed information about hook processing, payloads, and cloud communication to help with local development and troubleshooting.

Background / Context

When developing locally or troubleshooting hook issues, it's difficult to understand what's happening under the hood. Common scenarios include:

  • Troubleshooting why events aren't making it to LimaCharlie
  • Understanding payload formats from different providers (Claude Code, Cursor, Codex, OpenClaw, etc.)
  • Debugging hook invocation issues
  • Verifying cloud API communication
  • Understanding how tool_use vs prompt events are classified

Changes

New Commands

  • viberails debug - Enable debug mode
  • viberails debug --disable - Disable debug mode
  • viberails debug-clean - Remove accumulated debug log files

Features

  • Debug config field: New debug boolean in user config (opt-in, defaults to false)
  • Detailed logging: When enabled, logs full payloads, hook processing flow, cloud API requests/responses
  • Payload structure logging: Captures and classifies payloads to help understand provider formats
  • Secure storage: Debug logs stored in ~/.local/share/viberails/debug/ with restrictive permissions (0o700 directory, 0o600 files)
  • Unique filenames: Each hook invocation creates a unique log file (debug-{timestamp}-{random}.log) to preserve history
  • Zero overhead: When disabled, debug logging has no performance impact (log level filtering)
  • Cleanup command: debug-clean removes accumulated logs to free disk space

Bug Fixes

  • Fixed UTF-8 safe truncation for payload logging (prevents panic on multi-byte characters)
  • Fixed notification success log to only appear on actual success

Security Considerations

  • Debug mode is opt-in (disabled by default)
  • Debug directory has 0o700 permissions (owner only)
  • Debug log files have 0o600 permissions (owner read/write only)
  • Unique timestamped filenames prevent predictable paths
  • Warning displayed when enabling debug mode about sensitive data
  • Reminder to disable debug mode when done

Race Condition & Attack Prevention

  • Atomic file creation: Uses create_new + mode(0o600) on Unix to set permissions atomically at file creation, preventing TOCTOU race where file briefly has insecure default permissions
  • Symlink attack prevention: Uses O_EXCL semantics (create_new) which fails if the path already exists, preventing symlink attacks where an attacker could create a symlink to overwrite sensitive files
  • Atomic directory creation: Uses DirBuilder::mode() on Unix to create directory with secure permissions atomically
  • Permission verification: Always verifies/fixes directory permissions after creation to handle pre-existing directories with incorrect permissions
  • TOCTOU-safe cleanup: Log file cleanup ignores "not found" errors to handle race between directory listing and file removal

Usage

# Enable debug mode
viberails debug

# Use your AI coding tool - logs will be captured
# ...

# View debug logs
ls ~/.local/share/viberails/debug/
cat ~/.local/share/viberails/debug/debug-*.log

# Clean up when done
viberails debug-clean

# Disable debug mode
viberails debug --disable

Testing

  • Added comprehensive tests for payload classification across provider formats
  • Added tests for debug config (defaults, backwards compatibility, serialization)
  • Added tests for debug directory/file permissions
  • Added tests for cleanup functionality
  • Added tests for secure file creation (atomic permissions, symlink prevention)
  • All 222 tests pass, clippy clean

@tomaz-lc tomaz-lc force-pushed the feat/debug-mode-payload-logging branch 3 times, most recently from f188393 to a2003e8 Compare February 3, 2026 18:30
@tomaz-lc tomaz-lc marked this pull request as ready for review February 4, 2026 08:43
Copy link
Copy Markdown

@limacharlie-event-notifications limacharlie-event-notifications Bot left a comment

Choose a reason for hiding this comment

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

AI Code Review Summary

I reviewed this PR for security vulnerabilities, bugs/logic errors, performance issues, and missing tests.

Summary

This is a well-implemented debug mode feature with good security considerations. The code uses secure file creation patterns (atomic permissions, symlink prevention) and has comprehensive test coverage.

Security Analysis

Good security practices observed:

  • Debug mode is opt-in (disabled by default)
  • Directory permissions set to 0o700 (owner only)
  • File permissions set to 0o600 atomically at creation using create_new + mode()
  • Uses create_new (O_EXCL semantics) to prevent symlink attacks
  • Unique timestamped filenames prevent predictable paths
  • Proper TOCTOU race handling in cleanup

Found one issue:

  • Minor TOCTOU race in get_debug_log_path in loader.rs (see inline comment)

Test Coverage

The PR includes comprehensive tests for:

  • Payload classification across provider formats
  • Debug config defaults and backwards compatibility
  • Directory/file permissions on Unix
  • Symlink attack prevention
  • Cleanup functionality

This review was generated automatically by Claude Code.

Comment thread src/config/loader.rs Outdated
Comment on lines +288 to +305
// Create directory with restrictive permissions if it doesn't exist
if !debug_dir.exists() {
fs::create_dir_all(&debug_dir)
.with_context(|| format!("Unable to create debug directory: {}", debug_dir.display()))?;

// Set restrictive permissions on Unix (owner only)
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let perms = fs::Permissions::from_mode(0o700);
fs::set_permissions(&debug_dir, perms).with_context(|| {
format!(
"Unable to set permissions on debug directory: {}",
debug_dir.display()
)
})?;
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Low Priority: TOCTOU race condition in directory permission setting.

Unlike the implementation in src/logging.rs (lines 145-168), this function has a minor race: if the directory already exists (created by another process or previous run) with insecure permissions, this code path will not fix them because the set_permissions call is inside the if !debug_dir.exists() check.

The src/logging.rs implementation handles this correctly by always calling set_permissions after directory creation (see lines 161-168).

Consider moving the #[cfg(unix)] permission-setting block outside the if !debug_dir.exists() block so that pre-existing directories with incorrect permissions will also have their permissions corrected.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This has been addressed by the latest change (force push) - f778fcf.

- add `debug` config field (opt-in, defaults to false)
- add `viberails debug` command to enable/disable debug mode
- add `viberails debug-clean` command to remove accumulated debug logs
- log full payloads and hook processing details at debug level
- use secure debug directory (~/.local/share/viberails/debug/) with 0o700 permissions
- generate unique log filenames with timestamp and random suffix (debug-{ts}-{random}.log)
- set 0o600 permissions on debug log files for owner-only access
- add payload structure logging to understand provider formats
- fix UTF-8 safe truncation for payload logging (avoid panic on multi-byte chars)
- fix notification success log to only appear on actual success
- add comprehensive tests for payload classification and debug features

debug mode is useful for:
- troubleshooting hooks that aren't triggering or behaving unexpectedly
- understanding payload formats from different providers (Claude Code, Cursor, Codex, etc.)
- verifying cloud API communication and response handling
- checking tool_use vs prompt classification decisions
- testing new provider integrations
- diagnosing timing or connectivity issues

debug logging has zero overhead when disabled (log level filtering).

note: debug logs accumulate over time (one file per hook invocation).
use `viberails debug-clean` to remove old logs and free disk space.

usage:
  viberails debug             # enable debug mode
  viberails debug --disable   # disable debug mode
  viberails debug-clean       # remove all debug logs
  ls ~/.local/share/viberails/debug/  # view debug log files

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@tomaz-lc tomaz-lc force-pushed the feat/debug-mode-payload-logging branch from a2003e8 to f778fcf Compare February 4, 2026 11:33
@maximelb maximelb merged commit 80ceced into master Feb 4, 2026
24 checks passed
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.

2 participants