Configuration System - openguard-bot/openguard GitHub Wiki

Configuration System

AIMod features a comprehensive configuration system that allows fine-grained control over bot behavior at guild, channel, and user levels. This document covers all configuration options, management interfaces, and best practices.

🔧 Configuration Architecture

Hierarchical Configuration

AIMod uses a hierarchical configuration system:

Global Defaults
    ↓
Guild Configuration
    ↓
Channel-Specific Rules
    ↓
User-Specific Overrides

Storage Backend

Database Storage:

-- Guild configuration table
CREATE TABLE guild_config (
    guild_id BIGINT NOT NULL,
    key VARCHAR(255) NOT NULL,
    value JSONB,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (guild_id, key)
);

Caching Layer:

  • Redis Cache: 5-minute TTL for frequently accessed settings
  • In-Memory Cache: Hot configuration data
  • Write-Through: Immediate cache updates on configuration changes

Configuration Manager

# cogs/aimod_helpers/config_manager.py
async def get_guild_config_async(guild_id: int, key: str, default=None):
    """Get guild configuration with caching."""
    cache_key = f"guild_config:{guild_id}:{key}"
    
    # Check cache first
    cached_value = await get_cache(cache_key)
    if cached_value is not None:
        return json.loads(cached_value)
    
    # Query database
    async with get_connection() as conn:
        result = await conn.fetchval(
            "SELECT value FROM guild_config WHERE guild_id = $1 AND key = $2",
            guild_id, key
        )
    
    if result is not None:
        value = json.loads(result) if isinstance(result, str) else result
        await set_cache(cache_key, json.dumps(value), ttl=300)
        return value
    
    return default

async def set_guild_config(guild_id: int, key: str, value):
    """Set guild configuration with cache invalidation."""
    async with get_connection() as conn:
        await conn.execute("""
            INSERT INTO guild_config (guild_id, key, value, updated_at)
            VALUES ($1, $2, $3, CURRENT_TIMESTAMP)
            ON CONFLICT (guild_id, key)
            DO UPDATE SET value = $3, updated_at = CURRENT_TIMESTAMP
        """, guild_id, key, json.dumps(value))
    
    # Update cache
    cache_key = f"guild_config:{guild_id}:{key}"
    await set_cache(cache_key, json.dumps(value), ttl=300)

⚙️ Core Configuration Options

General Settings

ENABLED (Boolean)

  • Default: True
  • Description: Master switch for AI moderation
  • Usage: /config setting:enabled value:false

PREFIX (String)

  • Default: "!"
  • Description: Command prefix for the bot
  • Validation: 1-3 characters, no spaces
  • Usage: /prefix new_prefix:?

AI_MODEL (String)

  • Default: "github_copilot/gpt-4.1"
  • Description: AI model to use for moderation
  • Options:
    • github_copilot/gpt-4.1 - GitHub Copilot (recommended)
    • openai/gpt-4 - OpenAI GPT-4
    • anthropic/claude-3 - Anthropic Claude
    • google/gemini-pro - Google Gemini
  • Usage: /aimodel model:openai/gpt-4

RULES_TEXT (String)

  • Default: ""
  • Description: Server rules provided to AI for context
  • Max Length: 5000 characters
  • Usage: /config setting:rules_text value:"1. Be respectful..."

AI Moderation Settings

CONFIDENCE_THRESHOLD (Integer)

  • Default: 70
  • Range: 0-100
  • Description: Minimum confidence score for AI actions
  • Usage: /config setting:confidence_threshold value:80

AUTO_TIMEOUT_ENABLED (Boolean)

  • Default: True
  • Description: Enable automatic timeouts for violations
  • Usage: /config setting:auto_timeout_enabled value:true

TIMEOUT_DURATION (Integer)

  • Default: 3600 (1 hour)
  • Description: Default timeout duration in seconds
  • Range: 60-2419200 (1 minute to 28 days)
  • Usage: /config setting:timeout_duration value:7200

AUTO_BAN_ENABLED (Boolean)

  • Default: False
  • Description: Enable automatic bans for severe violations
  • Usage: /config setting:auto_ban_enabled value:true

BAN_THRESHOLD (Integer)

  • Default: 3
  • Description: Number of infractions before automatic ban
  • Range: 1-10
  • Usage: /config setting:ban_threshold value:5

DELETE_MESSAGES (Boolean)

  • Default: True
  • Description: Delete violating messages
  • Usage: /config setting:delete_messages value:false

Channel Configuration

AI_EXCLUDED_CHANNELS (Array)

  • Default: []
  • Description: Channels excluded from AI moderation
  • Format: Array of channel IDs
  • Usage: /aichannel exclude channel:#general

AI_CHANNEL_RULES (Object)

  • Default: {}
  • Description: Channel-specific rules override
  • Format: {channel_id: "custom rules"}
  • Usage: /aichannel setrules channel:#memes rules:"Be more lenient with humor"

Security Settings

Bot Detection Configuration

BOTDETECT_CONFIG = {
    "enabled": False,
    "keywords": [
        "discord.gg/",
        "free nitro",
        "click here",
        "dm me for",
        "check my bio"
    ],
    "action": "timeout",
    "timeout_duration": 3600,
    "log_channel": None,
    "whitelist_roles": [],
    "whitelist_users": []
}

Configuration Commands:

# Enable bot detection
/botdetect enabled:true

# Set action to ban
/botdetect action:ban

# Add keywords
/botdetect keywords:"new keyword,another keyword"

# Set whitelist roles
/botdetect whitelist_roles:@Moderator,@Trusted

Raid Defense Configuration

RAID_DEFENSE_CONFIG = {
    "enabled": False,
    "threshold": 10,        # Members joining
    "timeframe": 60,        # In 60 seconds
    "alert_channel": None,
    "auto_action": "lockdown"
}

Configuration Commands:

# Enable raid defense
/raiddefense enabled:true threshold:5 timeframe:30

# Set alert channel
/raiddefense alert_channel:#alerts

# Configure auto action
/raiddefense auto_action:ban

Logging Configuration

LOG_CHANNEL (Channel ID)

  • Default: None
  • Description: Channel for moderation logs
  • Usage: /logging channel:#mod-logs

WEBHOOK_URL (String)

  • Default: None
  • Description: Webhook URL for external logging
  • Usage: /modlog webhook_url:https://discord.com/api/webhooks/...

LOG_EVENTS (Array)

  • Default: ["ban", "kick", "timeout", "warn"]
  • Description: Events to log
  • Options: ban, kick, timeout, warn, join, leave, message_delete, role_change
  • Usage: /logging events:ban,kick,timeout,warn,join,leave

Message Rate Limiting

MESSAGE_RATE_CONFIG = {
    "enabled": False,
    "max_messages": 5,
    "timeframe": 10,        # seconds
    "action": "timeout",
    "timeout_duration": 300,
    "whitelist_roles": [],
    "escalation_enabled": True
}

🎛️ Configuration Interfaces

Discord Commands

/config - General Configuration

@app_commands.describe(
    setting="Configuration setting to view/modify",
    value="New value for the setting (optional)"
)
async def config(
    interaction: discord.Interaction,
    setting: str,
    value: str = None
):
    """View or modify guild configuration."""
    
    if value is None:
        # View current setting
        current_value = await get_guild_config_async(
            interaction.guild.id, 
            setting.upper()
        )
        await interaction.response.send_message(
            f"**{setting}:** `{current_value}`"
        )
    else:
        # Update setting
        await set_guild_config(
            interaction.guild.id,
            setting.upper(),
            parse_config_value(value)
        )
        await interaction.response.send_message(
            f"✅ Updated **{setting}** to `{value}`"
        )

/configlist - List All Settings

async def configlist(interaction: discord.Interaction):
    """Display all current configuration settings."""
    
    config_keys = [
        "ENABLED", "PREFIX", "AI_MODEL", "RULES_TEXT",
        "CONFIDENCE_THRESHOLD", "AUTO_TIMEOUT_ENABLED",
        "TIMEOUT_DURATION", "AUTO_BAN_ENABLED", "BAN_THRESHOLD"
    ]
    
    embed = discord.Embed(
        title="🔧 Guild Configuration",
        color=discord.Color.blue()
    )
    
    for key in config_keys:
        value = await get_guild_config_async(interaction.guild.id, key)
        embed.add_field(
            name=key.replace("_", " ").title(),
            value=f"`{value}`",
            inline=True
        )
    
    await interaction.response.send_message(embed=embed)

Web Dashboard

The web dashboard provides a user-friendly interface for configuration:

Configuration Sections:

  1. General Settings - Basic bot configuration
  2. AI Moderation - AI-specific settings
  3. Security Features - Bot detection and raid defense
  4. Logging & Analytics - Event logging configuration
  5. Channel Management - Channel-specific rules
  6. User Management - User permissions and overrides

Dashboard Features:

  • Real-time validation of configuration values
  • Bulk configuration import/export
  • Configuration templates for common setups
  • Change history and rollback capabilities
  • Permission-based access control

API Endpoints

Get Guild Configuration

@router.get("/guilds/{guild_id}/config")
async def get_guild_config(guild_id: int):
    """Get comprehensive guild configuration."""
    
    config = {
        "general": {
            "enabled": await get_guild_config_async(guild_id, "ENABLED", True),
            "prefix": await get_guild_config_async(guild_id, "PREFIX", "!"),
            "ai_model": await get_guild_config_async(guild_id, "AI_MODEL", DEFAULT_AI_MODEL)
        },
        "moderation": {
            "confidence_threshold": await get_guild_config_async(guild_id, "CONFIDENCE_THRESHOLD", 70),
            "auto_timeout_enabled": await get_guild_config_async(guild_id, "AUTO_TIMEOUT_ENABLED", True),
            "timeout_duration": await get_guild_config_async(guild_id, "TIMEOUT_DURATION", 3600)
        },
        "security": {
            "botdetect": await get_botdetect_config(guild_id),
            "raid_defense": await get_raid_defense_config(guild_id)
        }
    }
    
    return config

Update Guild Configuration

@router.put("/guilds/{guild_id}/config")
async def update_guild_config(
    guild_id: int,
    config: schemas.GuildConfigUpdate
):
    """Update guild configuration."""
    
    # Validate permissions
    if not await has_admin_permissions(guild_id, current_user):
        raise HTTPException(status_code=403, detail="Insufficient permissions")
    
    # Update configuration
    for key, value in config.dict(exclude_unset=True).items():
        await set_guild_config(guild_id, key.upper(), value)
    
    # Invalidate related caches
    await invalidate_guild_cache(guild_id)
    
    return {"status": "success", "updated": len(config.dict(exclude_unset=True))}

🔄 Configuration Migration

Version Migration

When configuration schema changes, migration scripts handle updates:

async def migrate_config_v1_to_v2(guild_id: int):
    """Migrate configuration from v1 to v2 format."""
    
    # Get old configuration
    old_config = await get_guild_config_async(guild_id, "CONFIG_V1")
    
    if old_config:
        # Transform to new format
        new_config = {
            "ENABLED": old_config.get("ai_enabled", True),
            "AI_MODEL": old_config.get("model", DEFAULT_AI_MODEL),
            "CONFIDENCE_THRESHOLD": old_config.get("threshold", 70)
        }
        
        # Set new configuration
        for key, value in new_config.items():
            await set_guild_config(guild_id, key, value)
        
        # Remove old configuration
        await delete_guild_config(guild_id, "CONFIG_V1")

Backup and Restore

async def backup_guild_config(guild_id: int) -> dict:
    """Create a backup of guild configuration."""
    
    async with get_connection() as conn:
        rows = await conn.fetch(
            "SELECT key, value FROM guild_config WHERE guild_id = $1",
            guild_id
        )
    
    return {
        "guild_id": guild_id,
        "timestamp": datetime.utcnow().isoformat(),
        "config": {row["key"]: json.loads(row["value"]) for row in rows}
    }

async def restore_guild_config(backup: dict):
    """Restore guild configuration from backup."""
    
    guild_id = backup["guild_id"]
    config = backup["config"]
    
    for key, value in config.items():
        await set_guild_config(guild_id, key, value)

🛡️ Configuration Security

Validation

All configuration values are validated before storage:

def validate_config_value(key: str, value: any) -> any:
    """Validate configuration value."""
    
    validators = {
        "CONFIDENCE_THRESHOLD": lambda v: 0 <= int(v) <= 100,
        "TIMEOUT_DURATION": lambda v: 60 <= int(v) <= 2419200,
        "PREFIX": lambda v: 1 <= len(str(v)) <= 3,
        "AI_MODEL": lambda v: v in ALLOWED_AI_MODELS
    }
    
    if key in validators:
        if not validators[key](value):
            raise ValueError(f"Invalid value for {key}: {value}")
    
    return value

Access Control

Configuration access is controlled by Discord permissions:

async def check_config_permissions(interaction: discord.Interaction) -> bool:
    """Check if user can modify configuration."""
    
    # Bot owners can always modify
    if interaction.user.id in BOT_OWNER_IDS:
        return True
    
    # Guild administrators can modify guild config
    if interaction.user.guild_permissions.administrator:
        return True
    
    # Check for specific config role
    config_role_id = await get_guild_config_async(
        interaction.guild.id, 
        "CONFIG_ROLE_ID"
    )
    
    if config_role_id:
        return any(role.id == config_role_id for role in interaction.user.roles)
    
    return False

Audit Logging

All configuration changes are logged:

async def log_config_change(
    guild_id: int,
    user_id: int,
    key: str,
    old_value: any,
    new_value: any
):
    """Log configuration change."""
    
    await insert_audit_log({
        "guild_id": guild_id,
        "user_id": user_id,
        "action": "CONFIG_CHANGE",
        "details": {
            "key": key,
            "old_value": old_value,
            "new_value": new_value
        },
        "timestamp": datetime.utcnow()
    })

Next: Security Features - Bot detection, raid defense, and security mechanisms