How Audit Logging Tracks User Actions in Claude-Code-Telegram: Implementation Guide

The bot implements a three-layer audit logging system using an AuditEvent dataclass, pluggable AuditStorage backends, and a high-level AuditLogger API to persist authentication attempts, commands, file accesses, and security violations to SQLite.

The RichardAtCT/claude-code-telegram repository captures every security-relevant activity through a comprehensive audit logging subsystem designed for forensics and real-time monitoring. This implementation provides structured event tracking with queryable storage, separating event definition, storage abstraction, and business logic into distinct maintainable layers. The audit logging architecture ensures that both successful operations and security violations leave a permanent, searchable trail.

Audit Logging Architecture Overview

The system organizes audit logging into five interconnected layers that handle everything from event definition to dashboard reporting:

Layer Responsibility Key Implementation
Event model Defines structured records for auditable actions. AuditEvent dataclass in src/security/audit.py (lines 22-34).
Storage abstraction Provides pluggable backends for testing and production. AuditStorage ABC and InMemoryAuditStorage in src/security/audit.py (lines 46-88).
Repository Persists events to SQLite and offers query helpers. AuditLogRepository.log_event in src/storage/repositories.py (lines 55-68).
High-level logger Business-logic API used throughout the bot. AuditLogger methods in src/security/audit.py (lines 89-212).
Integration points Middleware and handlers trigger logging. Authentication middleware in src/bot/middleware/auth.py (lines 66-74).

Defining Audit Events with AuditEvent

At the core of the system lies the AuditEvent dataclass, which serves as the canonical format for every log entry stored in src/security/audit.py.

@dataclass
class AuditEvent:
    timestamp: datetime                # UTC time of the event

    user_id: int                       # Telegram user ID

    event_type: str                    # e.g., "auth_attempt", "command", "file_access"

    success: bool                      # Pass/fail flag

    details: Dict[str, Any]            # Arbitrary payload (method, command, path, etc.)

    ip_address: Optional[str] = None
    session_id: Optional[str] = None
    risk_level: str = "low"            # "low", "medium", "high", "critical"

This definition enforces type safety while allowing flexible metadata storage through the details dictionary, ensuring every auditable action conforms to a consistent schema.

Pluggable Storage Backends

The audit logging system supports multiple storage implementations via the AuditStorage abstract base class defined in src/security/audit.py.

In-Memory Storage for Testing

The InMemoryAuditStorage class stores events in a Python list and automatically trims old entries. It also logs high-risk events via structlog for immediate visibility during test execution (lines 71-88).

SQLite Repository for Production

The AuditLogRepository in src/storage/repositories.py handles database persistence. It writes JSON-encoded event data to the audit_log table and provides filtered queries such as get_user_audit_log (lines 80-95) and get_recent_audit_log for administrative review.

High-Level AuditLogger API

The AuditLogger class wraps concrete storage implementations and exposes convenience methods for specific event types. This facade pattern simplifies audit logging calls throughout the bot's business logic.

Logging Authentication Attempts

The authentication middleware in src/bot/middleware/auth.py records every verification attempt by calling log_auth_attempt:

if audit_logger:
    await audit_logger.log_auth_attempt(
        user_id=user_id,
        success=authentication_successful,
        method="automatic",
        reason="message_received",
    )

This captures the authentication method, success status, and contextual reason for security analysis.

Recording Command Execution

When users execute system commands, the logger captures execution metadata and assesses risk based on command arguments:

await audit_logger.log_command(
    user_id=user_id,
    command="git",
    args=["clone", "repo.git"],
    success=True,
    working_directory="/tmp",
    execution_time=1.23,
    exit_code=0,
)

The method automatically evaluates risk levels based on command names and argument patterns, storing the result in the risk_level field.

Tracking File Access and Security Violations

Additional methods handle file system interactions and security policy breaches:

  • log_file_access() records path, action (read/write/delete), file size, and risk level.
  • log_security_violation() captures violation type, severity, and maps events to elevated risk levels.
  • log_rate_limit_breach() tracks limit types and usage ratios for abuse detection.

All methods route through self.storage.store_event(event), ensuring consistent persistence regardless of backend implementation.

SQLite Persistence Implementation

The AuditLogRepository.log_event method in src/storage/repositories.py handles database insertion using parameterized queries to prevent SQL injection:

async def log_event(self, audit_log: AuditLogModel) -> int:
    async with self.db.get_connection() as conn:
        event_data_json = json.dumps(audit_log.event_data) if audit_log.event_data else None
        cursor = await conn.execute(
            """
            INSERT INTO audit_log
            (user_id, event_type, event_data, success, timestamp, ip_address)
            VALUES (?, ?, ?, ?, ?, ?)
            """,
            (
                audit_log.user_id,
                audit_log.event_type,
                event_data_json,
                audit_log.success,
                audit_log.timestamp,
                audit_log.ip_address,
            ),
        )
        await conn.commit()
        return cursor.lastrowid

This implementation stores flexible JSON payloads in the event_data column while maintaining relational constraints on user IDs and timestamps.

Querying Audit Logs and Security Dashboards

The repository layer provides aggregation helpers for administrative interfaces. The AuditLogger exposes get_user_activity_summary() (lines 93-111) to retrieve total events, per-type counts, risk distribution, and success rates for specific users.

For system-wide monitoring, get_security_dashboard() (lines 43-81) aggregates recent events, violation counts, active user statistics, and top violation types. These endpoints power the bot's /status command and administrative dashboards:

recent = await storage.audit.get_recent_audit_log(hours=24)
dashboard = await audit_logger.get_security_dashboard()

Integration Points

The storage facade in src/storage/facade.py exposes the audit logger to the application via self.audit = AuditLogRepository(db), making it accessible to handlers and middleware throughout the bot. Unit tests in tests/unit/test_security/test_audit.py verify that each logging method correctly persists events to the configured storage backend.

Summary

  • Structured Events: The AuditEvent dataclass in src/security/audit.py provides a type-safe, extensible schema for all security-relevant activities.
  • Pluggable Storage: The AuditStorage abstraction supports both InMemoryAuditStorage for unit tests and AuditLogRepository for production SQLite persistence.
  • Comprehensive Coverage: The AuditLogger API captures authentication attempts, command executions, file accesses, rate-limit breaches, and security violations.
  • Database Persistence: Events serialize to JSON and store in the audit_log table via parameterized SQLite queries in src/storage/repositories.py.
  • Administrative Visibility: Built-in aggregation methods enable user activity summaries and security dashboards for real-time monitoring.

Frequently Asked Questions

Where are audit logs stored in the Claude-Code-Telegram bot?

Audit logs persist to a SQLite database table named audit_log via the AuditLogRepository class in src/storage/repositories.py. For testing scenarios, the system uses InMemoryAuditStorage to avoid database dependencies while still validating logging logic.

What event types does the audit logging system capture?

The system captures authentication attempts, command executions, file system accesses, security policy violations, and rate-limit breaches. Each event includes metadata such as user ID, timestamp, success status, risk level, and contextual details in a JSON payload.

How does the bot determine risk levels for audit events?

The AuditLogger class assesses risk based on event context. For commands, it evaluates the executable name and arguments; for file access, it considers the operation type and path sensitivity. Risk levels map to "low", "medium", "high", or "critical" classifications stored in the risk_level field of every AuditEvent.

Can administrators query audit logs for specific users?

Yes. The AuditLogRepository.get_user_audit_log method in src/storage/repositories.py provides filtered queries by user ID, and the AuditLogger.get_user_activity_summary method aggregates statistics including event counts, risk distribution, and success rates for individual users. These methods support compliance auditing and security investigations.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →