ransomware defense

Deploying Ransomware Canary Files

Deploys and monitors ransomware canary files across critical directories using Python's watchdog library for real-time filesystem event detection. Places strategically named decoy files that mimic high-value targets (financial records, credentials, database exports) in locations ransomware typically enumerates first. Monitors for any read, modify, rename, or delete operations on canary files and triggers immediate alerts via email, Slack webhook, or syslog when interaction is detected, providing early warning before full encryption begins.

canary-filesdeceptiondefensedetectionearly-warningransomwarewatchdog
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

When to Use

  • Deploying proactive ransomware detection on file servers, NAS devices, or endpoint systems
  • Building an early-warning system that detects ransomware before it encrypts business-critical data
  • Supplementing EDR solutions with lightweight canary file monitoring on systems where agents cannot be deployed
  • Testing ransomware incident response procedures by simulating canary file triggers
  • Monitoring shared drives, home directories, and backup volumes for unauthorized file operations

Do not use as a replacement for endpoint protection, backup strategy, or network segmentation. Canary files are a detection layer, not a prevention mechanism.

Prerequisites

  • Python 3.8+ with pip
  • watchdog library (pip install watchdog)
  • Write access to directories where canary files will be placed
  • SMTP server credentials or Slack webhook URL for alerting
  • Administrative access for placing canaries in system directories

Workflow

Step 1: Generate Canary Files

Create decoy files with realistic names and content that attract ransomware scanners. Files should have names like Passwords.xlsx, Financial_Report_2026.docx, backup_credentials.csv and contain plausible-looking but fake data. Place them in directories ransomware typically targets first: user desktops, Documents folders, network share roots, and backup paths.

Step 2: Deploy Filesystem Monitor

Use Python's watchdog library with a custom FileSystemEventHandler that watches canary file paths. The handler triggers on on_modified, on_deleted, on_moved, and on_created events for canary files. Any legitimate user or process should never touch these files, so any interaction is a high-confidence indicator of ransomware or unauthorized access.

Step 3: Configure Alert Pipeline

Wire the filesystem monitor to multiple alert channels: email via SMTP, Slack webhook POST, syslog forwarding to SIEM, and local log file. Include the triggering event type, file path, timestamp, and process information (when available) in alert payloads.

Step 4: Validate and Test

Simulate ransomware behavior by programmatically modifying, renaming, and deleting canary files to verify the detection pipeline fires correctly. Measure time-to-alert and validate alert delivery across all configured channels.

Key Concepts

Term Definition
Canary File A decoy file placed in a monitored directory that triggers an alert when accessed, modified, or deleted
Watchdog Python library that monitors filesystem events using OS-native APIs (inotify on Linux, FSEvents on macOS, ReadDirectoryChangesW on Windows)
Honey File Synonym for canary file; a fake document designed to attract and detect malicious activity
Entropy Check Measuring randomness in file content to detect encryption (ransomware produces high-entropy output)

Tools & Systems

  • watchdog: Python filesystem monitoring library using OS-native event APIs
  • smtplib: Python standard library for SMTP email alerting
  • requests: HTTP library for Slack webhook integration
  • hashlib: SHA-256 hashing for canary file integrity verification
  • psutil: Process information gathering when canary file access is detected

Output Format

RANSOMWARE CANARY ALERT
========================
Timestamp: 2026-03-11T14:23:07Z
Event: FILE_MODIFIED
Canary File: /srv/shares/finance/Passwords.xlsx
Directory: /srv/shares/finance
SHA-256 Before: a3f2...8b4c
SHA-256 After: 7e91...2d3f
Alert Channels: [email, slack, syslog]
Action: Investigate immediately - potential ransomware activity
Source materials

References and resources

Everything below is rendered for inspection. Script files are read-only and never run.

References 1

api-reference.md2.9 KB

API Reference: Deploying Ransomware Canary Files

Canary File Deployment

Function Parameters Returns
deploy_canary_files(target_dirs, custom_files) List of directories, optional custom file dict Manifest with deployed file paths and hashes
compute_sha256(filepath) File path string SHA-256 hex digest
compute_entropy(filepath) File path string Shannon entropy float (0-8)

Monitoring Functions

Function Parameters Returns
start_monitoring(manifest_path, config) Path to manifest JSON, alert config dict Blocks until interrupted
verify_canary_integrity(manifest_path) Path to manifest JSON Dict with intact/modified/missing counts
simulate_ransomware_test(manifest_path) Path to manifest JSON List of test results

CanaryFileHandler Events

Event Handler Method Trigger
File modified on_modified(event) Content change detected
File deleted on_deleted(event) Canary file removed
File renamed on_moved(event) Canary file renamed or moved
New file created on_created(event) Ransom note detection in monitored dirs

Alert Channels

Channel Function Required Config
Slack send_slack_alert(data, webhook_url) slack_webhook URL
Email send_email_alert(data, host, port, sender, recipients) SMTP server details
Syslog send_syslog_alert(data, server, port) Syslog server address
File Automatic Writes to canary_alerts.jsonl

Ransomware Extension Detection

Extensions Monitored
.encrypted, .locked, .lockbit, .crypt, .enc
.ransom, .pay, .aes, .rsa, .cry
.ryk, .revil, .conti, .hive, .black, .basta

CLI Usage

# Deploy canary files
python agent.py --action deploy --dirs /srv/shares /home/admin/Documents
 
# Monitor canary files with Slack alerts
python agent.py --action monitor --slack-webhook https://hooks.slack.com/...
 
# Verify canary file integrity
python agent.py --action verify
 
# Test detection pipeline
python agent.py --action test

Python Libraries

Library Version Purpose
watchdog >=3.0 Filesystem event monitoring
requests >=2.28 Slack webhook integration
psutil >=5.9 Process information gathering
hashlib stdlib SHA-256 file hashing
smtplib stdlib SMTP email alerts

References

Scripts 1

agent.py20.8 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Ransomware canary file deployment and monitoring agent.

Deploys decoy files across critical directories and monitors them using
watchdog for real-time filesystem event detection. Any interaction with
canary files triggers alerts via email, Slack, and syslog.
"""

import os
import sys
import json
import time
import hashlib
import logging
import smtplib
import argparse
import platform
from pathlib import Path
from email.mime.text import MIMEText
from datetime import datetime, timezone

try:
    from watchdog.observers import Observer
    from watchdog.events import FileSystemEventHandler
    HAS_WATCHDOG = True
except ImportError:
    HAS_WATCHDOG = False

try:
    import requests
    HAS_REQUESTS = True
except ImportError:
    HAS_REQUESTS = False

try:
    import psutil
    HAS_PSUTIL = True
except ImportError:
    HAS_PSUTIL = False

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(message)s",
    handlers=[
        logging.StreamHandler(),
        logging.FileHandler("canary_monitor.log"),
    ],
)
logger = logging.getLogger(__name__)

CANARY_FILE_TEMPLATES = {
    "Passwords.xlsx": b"PK\x03\x04" + b"\x00" * 26 + b"[Content_Types].xml" + os.urandom(512),
    "Financial_Report_2026.docx": b"PK\x03\x04" + b"\x00" * 26 + b"word/document.xml" + os.urandom(512),
    "backup_credentials.csv": (
        b"hostname,username,password,last_rotated\n"
        b"dc01.corp.local,svc_backup,R3st0re$ecur3!2026,2026-01-15\n"
        b"sql-prod-01,sa,Pr0d_DB#Access!,2026-02-01\n"
        b"vpn-gateway,admin,VPN@dm1n_2026!,2026-03-01\n"
        b"nas-backup,root,B4ckup_N4S!2026,2025-12-20\n"
    ),
    "Employee_SSN_List.xlsx": b"PK\x03\x04" + b"\x00" * 26 + b"xl/worksheets/sheet1.xml" + os.urandom(512),
    "tax_returns_2025.pdf": b"%PDF-1.7\n1 0 obj\n<< /Type /Catalog >>\nendobj\n" + os.urandom(256),
    "bitcoin_wallet_seed.txt": (
        b"BIP39 Mnemonic Seed Phrase (DO NOT SHARE)\n"
        b"abandon ability able about above absent absorb abstract absurd abuse\n"
        b"access accident account accuse achieve acid acoustic acquire across act\n"
        b"Wallet Address: bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh\n"
    ),
    "database_export_prod.sql": (
        b"-- MySQL dump 10.13  Distrib 8.0.36\n"
        b"-- Host: db-prod-01.internal    Database: customer_data\n"
        b"CREATE TABLE customers (\n"
        b"  id INT PRIMARY KEY AUTO_INCREMENT,\n"
        b"  ssn VARCHAR(11) NOT NULL,\n"
        b"  credit_card VARCHAR(19),\n"
        b"  balance DECIMAL(10,2)\n"
        b");\n"
    ),
    "AWS_Access_Keys.csv": (
        b"User Name,Access Key ID,Secret Access Key\n"
        b"svc-prod-deploy,AKIAIOSFODNN7EXAMPLE,wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY\n"
        b"svc-backup,AKIAI44QH8DHBEXAMPLE,je7MtGbClwBF/2Zp9Utk/h3yCo8nvbEXAMPLEKEY\n"
    ),
}


def compute_sha256(filepath):
    """Compute SHA-256 hash of a file."""
    sha256 = hashlib.sha256()
    try:
        with open(filepath, "rb") as f:
            for chunk in iter(lambda: f.read(65536), b""):
                sha256.update(chunk)
        return sha256.hexdigest()
    except (FileNotFoundError, PermissionError):
        return "file_not_accessible"


def compute_entropy(filepath):
    """Calculate Shannon entropy of file content to detect encryption."""
    try:
        with open(filepath, "rb") as f:
            data = f.read()
    except (FileNotFoundError, PermissionError):
        return 0.0
    if not data:
        return 0.0
    from collections import Counter
    import math
    byte_counts = Counter(data)
    length = len(data)
    entropy = -sum(
        (count / length) * math.log2(count / length)
        for count in byte_counts.values()
        if count > 0
    )
    return round(entropy, 4)


def get_process_info():
    """Get information about processes that may have accessed canary files."""
    if not HAS_PSUTIL:
        return {"error": "psutil not installed"}
    suspicious = []
    for proc in psutil.process_iter(["pid", "name", "username", "cmdline", "create_time"]):
        try:
            info = proc.info
            if info["create_time"] and (time.time() - info["create_time"]) < 30:
                suspicious.append({
                    "pid": info["pid"],
                    "name": info["name"],
                    "username": info["username"],
                    "cmdline": " ".join(info["cmdline"] or []),
                    "age_seconds": round(time.time() - info["create_time"], 1),
                })
        except (psutil.NoSuchProcess, psutil.AccessDenied):
            continue
    return suspicious[:10]


def deploy_canary_files(target_dirs, custom_files=None):
    """Deploy canary files to specified directories."""
    templates = dict(CANARY_FILE_TEMPLATES)
    if custom_files:
        templates.update(custom_files)

    deployed = []
    for directory in target_dirs:
        dir_path = Path(directory)
        if not dir_path.exists():
            logger.warning("Directory does not exist: %s", directory)
            continue
        if not os.access(directory, os.W_OK):
            logger.warning("No write access to: %s", directory)
            continue

        for filename, content in templates.items():
            filepath = dir_path / filename
            if filepath.exists():
                logger.info("Canary already exists: %s", filepath)
                deployed.append(str(filepath))
                continue
            try:
                with open(filepath, "wb") as f:
                    f.write(content)
                if platform.system() != "Windows":
                    os.chmod(filepath, 0o644)
                sha256 = compute_sha256(str(filepath))
                deployed.append(str(filepath))
                logger.info("Deployed canary: %s (SHA-256: %s)", filepath, sha256[:16])
            except (PermissionError, OSError) as e:
                logger.error("Failed to deploy %s: %s", filepath, e)

    manifest = {
        "deployed_at": datetime.now(timezone.utc).isoformat(),
        "canary_count": len(deployed),
        "directories": target_dirs,
        "files": deployed,
        "hashes": {f: compute_sha256(f) for f in deployed},
    }
    manifest_path = Path("canary_manifest.json")
    with open(manifest_path, "w") as f:
        json.dump(manifest, f, indent=2)
    logger.info("Deployed %d canary files, manifest saved to %s", len(deployed), manifest_path)
    return manifest


def send_email_alert(alert_data, smtp_host, smtp_port, sender, recipients, password=None):
    """Send alert email via SMTP."""
    subject = f"RANSOMWARE CANARY ALERT: {alert_data['event_type']} on {alert_data['canary_file']}"
    body = json.dumps(alert_data, indent=2, default=str)
    msg = MIMEText(body)
    msg["Subject"] = subject
    msg["From"] = sender
    msg["To"] = ", ".join(recipients)
    try:
        if smtp_port == 465:
            server = smtplib.SMTP_SSL(smtp_host, smtp_port, timeout=10)
        else:
            server = smtplib.SMTP(smtp_host, smtp_port, timeout=10)
            server.ehlo()
            if smtp_port == 587:
                server.starttls()
                server.ehlo()
        if password:
            server.login(sender, password)
        server.sendmail(sender, recipients, msg.as_string())
        server.quit()
        logger.info("Email alert sent to %s", recipients)
        return True
    except Exception as e:
        logger.error("Email alert failed: %s", e)
        return False


def send_slack_alert(alert_data, webhook_url):
    """Send alert to Slack via incoming webhook."""
    if not HAS_REQUESTS:
        logger.error("requests library not installed, cannot send Slack alert")
        return False
    payload = {
        "text": f":rotating_light: *RANSOMWARE CANARY ALERT*",
        "blocks": [
            {
                "type": "header",
                "text": {"type": "plain_text", "text": "Ransomware Canary File Triggered"}
            },
            {
                "type": "section",
                "fields": [
                    {"type": "mrkdwn", "text": f"*Event:*\n{alert_data['event_type']}"},
                    {"type": "mrkdwn", "text": f"*File:*\n`{alert_data['canary_file']}`"},
                    {"type": "mrkdwn", "text": f"*Time:*\n{alert_data['timestamp']}"},
                    {"type": "mrkdwn", "text": f"*Host:*\n{alert_data.get('hostname', 'unknown')}"},
                ]
            },
            {
                "type": "section",
                "text": {
                    "type": "mrkdwn",
                    "text": f"*Immediate Action Required:* Investigate potential ransomware activity on `{alert_data.get('hostname', 'unknown')}`"
                }
            }
        ]
    }
    try:
        resp = requests.post(webhook_url, json=payload, timeout=10)
        if resp.status_code == 200:
            logger.info("Slack alert sent successfully")
            return True
        logger.error("Slack alert failed: %d %s", resp.status_code, resp.text)
        return False
    except Exception as e:
        logger.error("Slack alert failed: %s", e)
        return False


def send_syslog_alert(alert_data, syslog_server="127.0.0.1", syslog_port=514):
    """Send alert to syslog server via UDP."""
    import socket
    priority = 8 * 4 + 1  # facility=security, severity=alert
    message = (
        f"<{priority}>1 {alert_data['timestamp']} {alert_data.get('hostname', '-')} "
        f"canary-monitor - - - RANSOMWARE_CANARY event={alert_data['event_type']} "
        f"file={alert_data['canary_file']} "
        f"hash_before={alert_data.get('hash_before', 'N/A')} "
        f"hash_after={alert_data.get('hash_after', 'N/A')}"
    )
    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        sock.settimeout(10)
        sock.sendto(message.encode("utf-8"), (syslog_server, syslog_port))
        sock.close()
        logger.info("Syslog alert sent to %s:%d", syslog_server, syslog_port)
        return True
    except Exception as e:
        logger.error("Syslog alert failed: %s", e)
        return False


class CanaryFileHandler(FileSystemEventHandler):
    """Watchdog event handler for canary file monitoring."""

    def __init__(self, canary_files, config):
        super().__init__()
        self.canary_files = {str(Path(f).resolve()): compute_sha256(f) for f in canary_files}
        self.config = config
        self.alert_count = 0
        self.last_alert_time = {}

    def _is_canary(self, path):
        resolved = str(Path(path).resolve())
        return resolved in self.canary_files

    def _rate_limit_check(self, path, cooldown=10):
        now = time.time()
        last = self.last_alert_time.get(path, 0)
        if now - last < cooldown:
            return False
        self.last_alert_time[path] = now
        return True

    def _build_alert(self, event_type, src_path, dest_path=None):
        alert = {
            "timestamp": datetime.now(timezone.utc).isoformat(),
            "event_type": event_type,
            "canary_file": src_path,
            "hostname": platform.node(),
            "platform": platform.system(),
            "hash_before": self.canary_files.get(str(Path(src_path).resolve()), "unknown"),
            "hash_after": compute_sha256(src_path) if os.path.exists(src_path) else "file_deleted",
            "entropy_after": compute_entropy(src_path) if os.path.exists(src_path) else 0.0,
            "alert_number": self.alert_count + 1,
        }
        if dest_path:
            alert["destination"] = dest_path
        if HAS_PSUTIL:
            alert["recent_processes"] = get_process_info()
        return alert

    def _dispatch_alert(self, alert):
        self.alert_count += 1
        logger.critical(
            "CANARY TRIGGERED: %s on %s (alert #%d)",
            alert["event_type"], alert["canary_file"], self.alert_count
        )
        with open("canary_alerts.jsonl", "a") as f:
            f.write(json.dumps(alert, default=str) + "\n")

        if self.config.get("slack_webhook"):
            send_slack_alert(alert, self.config["slack_webhook"])
        if self.config.get("smtp_host"):
            send_email_alert(
                alert,
                self.config["smtp_host"],
                self.config.get("smtp_port", 587),
                self.config.get("smtp_sender", "canary@localhost"),
                self.config.get("smtp_recipients", []),
                self.config.get("smtp_password"),
            )
        if self.config.get("syslog_server"):
            send_syslog_alert(
                alert,
                self.config["syslog_server"],
                self.config.get("syslog_port", 514),
            )

    def on_modified(self, event):
        if event.is_directory:
            return
        if self._is_canary(event.src_path) and self._rate_limit_check(event.src_path):
            alert = self._build_alert("FILE_MODIFIED", event.src_path)
            high_entropy = alert.get("entropy_after", 0) > 7.5
            if high_entropy:
                alert["encryption_suspected"] = True
                alert["severity"] = "critical"
            self._dispatch_alert(alert)

    def on_deleted(self, event):
        if event.is_directory:
            return
        if self._is_canary(event.src_path) and self._rate_limit_check(event.src_path):
            alert = self._build_alert("FILE_DELETED", event.src_path)
            alert["severity"] = "critical"
            self._dispatch_alert(alert)

    def on_moved(self, event):
        if event.is_directory:
            return
        if self._is_canary(event.src_path) and self._rate_limit_check(event.src_path):
            alert = self._build_alert("FILE_RENAMED", event.src_path, event.dest_path)
            extension = Path(event.dest_path).suffix.lower()
            ransomware_extensions = {
                ".encrypted", ".locked", ".lockbit", ".crypt", ".enc",
                ".ransom", ".pay", ".aes", ".rsa", ".cry", ".ryk",
                ".revil", ".conti", ".hive", ".black", ".basta",
            }
            if extension in ransomware_extensions:
                alert["ransomware_extension_detected"] = extension
                alert["severity"] = "critical"
            self._dispatch_alert(alert)

    def on_created(self, event):
        if event.is_directory:
            return
        parent = str(Path(event.src_path).parent)
        ransom_note_patterns = [
            "readme", "decrypt", "restore", "recover", "how_to",
            "ransom", "locked", "unlock", "pay", "instruction",
        ]
        basename = Path(event.src_path).stem.lower()
        if any(pattern in basename for pattern in ransom_note_patterns):
            for canary_dir in set(str(Path(c).parent) for c in self.canary_files):
                if parent == canary_dir:
                    alert = self._build_alert("RANSOM_NOTE_DETECTED", event.src_path)
                    alert["severity"] = "critical"
                    alert["indicator"] = "Ransom note dropped in monitored directory"
                    self._dispatch_alert(alert)
                    break


def start_monitoring(manifest_path, config):
    """Start real-time canary file monitoring."""
    if not HAS_WATCHDOG:
        logger.error("watchdog library required: pip install watchdog")
        sys.exit(1)

    with open(manifest_path) as f:
        manifest = json.load(f)

    canary_files = manifest["files"]
    if not canary_files:
        logger.error("No canary files found in manifest")
        sys.exit(1)

    watch_dirs = set()
    for canary in canary_files:
        parent = str(Path(canary).parent)
        if os.path.isdir(parent):
            watch_dirs.add(parent)

    handler = CanaryFileHandler(canary_files, config)
    observer = Observer()
    for directory in watch_dirs:
        observer.schedule(handler, directory, recursive=False)
        logger.info("Watching directory: %s", directory)

    logger.info("Monitoring %d canary files across %d directories", len(canary_files), len(watch_dirs))
    observer.start()
    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        observer.stop()
        logger.info("Monitoring stopped. Total alerts: %d", handler.alert_count)
    observer.join()


def verify_canary_integrity(manifest_path):
    """Verify all canary files match their original hashes."""
    with open(manifest_path) as f:
        manifest = json.load(f)
    results = {"checked": 0, "intact": 0, "modified": 0, "missing": 0, "details": []}
    for filepath, original_hash in manifest.get("hashes", {}).items():
        results["checked"] += 1
        if not os.path.exists(filepath):
            results["missing"] += 1
            results["details"].append({"file": filepath, "status": "MISSING"})
        else:
            current_hash = compute_sha256(filepath)
            if current_hash == original_hash:
                results["intact"] += 1
                results["details"].append({"file": filepath, "status": "INTACT"})
            else:
                results["modified"] += 1
                results["details"].append({
                    "file": filepath,
                    "status": "MODIFIED",
                    "original_hash": original_hash,
                    "current_hash": current_hash,
                    "entropy": compute_entropy(filepath),
                })
    return results


def simulate_ransomware_test(manifest_path):
    """Simulate ransomware activity against canary files for testing."""
    with open(manifest_path) as f:
        manifest = json.load(f)
    test_results = []
    for filepath in manifest.get("files", [])[:2]:
        if not os.path.exists(filepath):
            continue
        test_file = filepath + ".test_canary"
        try:
            import shutil
            shutil.copy2(filepath, test_file)
            with open(test_file, "ab") as f:
                f.write(os.urandom(64))
            test_results.append({
                "file": filepath,
                "test_action": "modified_copy",
                "test_file": test_file,
                "status": "triggered",
            })
            os.remove(test_file)
        except Exception as e:
            test_results.append({"file": filepath, "error": str(e)})
    return test_results


def main():
    parser = argparse.ArgumentParser(description="Ransomware Canary File Deployment and Monitoring Agent")
    parser.add_argument("--action", choices=["deploy", "monitor", "verify", "test"],
                        default="deploy", help="Action to perform")
    parser.add_argument("--dirs", nargs="+", help="Directories to deploy canary files")
    parser.add_argument("--manifest", default="canary_manifest.json", help="Canary manifest file path")
    parser.add_argument("--config", help="JSON config file for alert settings")
    parser.add_argument("--slack-webhook", help="Slack incoming webhook URL")
    parser.add_argument("--smtp-host", help="SMTP server hostname")
    parser.add_argument("--smtp-port", type=int, default=587)
    parser.add_argument("--smtp-sender", help="Alert sender email")
    parser.add_argument("--smtp-recipients", nargs="+", help="Alert recipient emails")
    parser.add_argument("--syslog-server", help="Syslog server address")
    args = parser.parse_args()

    config = {}
    if args.config and os.path.exists(args.config):
        with open(args.config) as f:
            config = json.load(f)
    if args.slack_webhook:
        config["slack_webhook"] = args.slack_webhook
    if args.smtp_host:
        config["smtp_host"] = args.smtp_host
        config["smtp_port"] = args.smtp_port
        config["smtp_sender"] = args.smtp_sender
        config["smtp_recipients"] = args.smtp_recipients or []
    if args.syslog_server:
        config["syslog_server"] = args.syslog_server

    if args.action == "deploy":
        if not args.dirs:
            print("Usage: python agent.py --action deploy --dirs /path/to/dir1 /path/to/dir2")
            print("\nExample:")
            print("  python agent.py --action deploy --dirs /srv/shares/finance /home/admin/Documents")
            return
        manifest = deploy_canary_files(args.dirs)
        print(json.dumps(manifest, indent=2))

    elif args.action == "monitor":
        if not os.path.exists(args.manifest):
            print(f"Manifest not found: {args.manifest}")
            print("Run --action deploy first to create canary files")
            return
        start_monitoring(args.manifest, config)

    elif args.action == "verify":
        if not os.path.exists(args.manifest):
            print(f"Manifest not found: {args.manifest}")
            return
        results = verify_canary_integrity(args.manifest)
        print(json.dumps(results, indent=2))
        if results["modified"] > 0 or results["missing"] > 0:
            print(f"\n[ALERT] {results['modified']} modified, {results['missing']} missing canary files!")

    elif args.action == "test":
        if not os.path.exists(args.manifest):
            print(f"Manifest not found: {args.manifest}")
            return
        results = simulate_ransomware_test(args.manifest)
        print(json.dumps(results, indent=2))


if __name__ == "__main__":
    main()
Keep exploring