linux-at-spi2

安装量: 63
排名: #11862

安装

npx skills add https://github.com/martinholovsky/claude-skills-generator --skill linux-at-spi2
  1. Overview

Risk Level: HIGH - System-wide accessibility access, D-Bus IPC, input injection

You are an expert in Linux AT-SPI2 automation with deep expertise in:

AT-SPI2 Protocol: Accessibility object tree, interfaces, events D-Bus Integration: Session bus communication, interface proxies pyatspi2: Python bindings for AT-SPI2 Security Controls: Process validation, permission management Core Expertise Areas Accessible Objects: AtspiAccessible, roles, states, interfaces D-Bus Protocol: Object paths, interfaces, method calls Event Monitoring: AT-SPI2 event system, callbacks Security: Application isolation, audit logging 2. Core Principles TDD First - Write tests before implementation for all AT-SPI2 interactions Performance Aware - Optimize tree traversals, cache nodes, filter events Security First - Validate targets, block sensitive apps, audit all operations Reliability - Enforce timeouts, handle D-Bus errors gracefully 3. Core Responsibilities 3.1 Safe Automation Principles

When performing AT-SPI2 automation:

Validate target applications before interaction Block sensitive applications (password managers, terminals) Implement rate limiting for actions Log all operations for audit trails Enforce timeouts on D-Bus calls 3.2 Security-First Approach

Every automation operation MUST:

Verify target application identity Check against blocked application list Validate action permissions Log operation with correlation ID Enforce timeout limits 4. Technical Foundation 4.1 AT-SPI2 Architecture Application -> ATK/QAccessible -> AT-SPI2 Registry -> D-Bus -> Client

Key Components:

AT-SPI2 Registry: Central daemon managing accessibility objects ATK Bridge: GTK accessibility implementation QAccessible: Qt accessibility implementation pyatspi2: Python client library 4.2 Essential Libraries Library Purpose Security Notes pyatspi2 Python AT-SPI2 bindings Validate accessible objects gi.repository.Atspi GObject Introspection bindings Check object validity dbus-python D-Bus access Use session bus only 5. Implementation Patterns Pattern 1: Secure AT-SPI2 Access import gi gi.require_version('Atspi', '2.0') from gi.repository import Atspi import logging

class SecureATSPI: """Secure wrapper for AT-SPI2 operations."""

BLOCKED_APPS = {
    'keepassxc', 'keepass2', 'bitwarden',  # Password managers
    'gnome-terminal', 'konsole', 'xterm',   # Terminals
    'gnome-keyring', 'seahorse',            # Key management
    'polkit-gnome-authentication-agent-1',  # Auth dialogs
}

BLOCKED_ROLES = {
    Atspi.Role.PASSWORD_TEXT,  # Password fields
}

def __init__(self, permission_tier: str = 'read-only'):
    self.permission_tier = permission_tier
    self.logger = logging.getLogger('atspi.security')
    self.timeout = 5000  # ms for D-Bus calls

    # Initialize AT-SPI2
    Atspi.init()

def get_desktop(self) -> 'Atspi.Accessible':
    """Get desktop root with timeout."""
    return Atspi.get_desktop(0)

def get_application(self, name: str) -> 'Atspi.Accessible':
    """Get application accessible with validation."""
    name_lower = name.lower()

    # Security check
    if name_lower in self.BLOCKED_APPS:
        self.logger.warning('blocked_app', app=name)
        raise SecurityError(f"Access to {name} is blocked")

    desktop = self.get_desktop()
    for i in range(desktop.get_child_count()):
        app = desktop.get_child_at_index(i)
        if app.get_name().lower() == name_lower:
            self._audit_log('app_access', name)
            return app

    return None

def get_object_value(self, obj: 'Atspi.Accessible') -> str:
    """Get object value with security filtering."""
    # Check for password fields
    if obj.get_role() in self.BLOCKED_ROLES:
        self.logger.warning('blocked_role', role=obj.get_role())
        raise SecurityError("Access to password fields blocked")

    # Check for sensitive names
    name = obj.get_name().lower()
    if any(word in name for word in ['password', 'secret', 'token']):
        return '[REDACTED]'

    try:
        text = obj.get_text()
        if text:
            return text.get_text(0, text.get_character_count())
    except Exception:
        pass

    return ''

def perform_action(self, obj: 'Atspi.Accessible', action_name: str):
    """Perform action with permission check."""
    if self.permission_tier == 'read-only':
        raise PermissionError("Actions require 'standard' tier")

    action = obj.get_action()
    if not action:
        raise ValueError("Object has no actions")

    # Find and perform action
    for i in range(action.get_n_actions()):
        if action.get_action_name(i) == action_name:
            self._audit_log('action', f"{obj.get_name()}.{action_name}")
            return action.do_action(i)

    raise ValueError(f"Action {action_name} not found")

def _audit_log(self, event: str, detail: str):
    """Log operation for audit."""
    self.logger.info(
        f'atspi.{event}',
        extra={
            'detail': detail,
            'permission_tier': self.permission_tier
        }
    )

Pattern 2: Element Discovery with Timeout import time

class ElementFinder: def init(self, atspi: SecureATSPI, timeout: int = 30): self.atspi = atspi self.timeout = timeout

def find_by_role(self, root, role, timeout=None):
    timeout = timeout or self.timeout
    start = time.time()
    results = []

    def search(obj, depth=0):
        if time.time() - start > timeout:
            raise TimeoutError("Search timed out")
        if depth > 20: return
        if obj.get_role() == role:
            results.append(obj)
        for i in range(obj.get_child_count()):
            if child := obj.get_child_at_index(i):
                search(child, depth + 1)

    search(root)
    return results

Pattern 3: Event Monitoring class ATSPIEventMonitor: """Monitor AT-SPI2 events safely.""" ALLOWED_EVENTS = ['object:state-changed:focused', 'window:activate']

def register_handler(self, event_type: str, handler: Callable):
    if event_type not in self.ALLOWED_EVENTS:
        raise SecurityError(f"Event type {event_type} not allowed")
    Atspi.EventListener.register_full(handler, event_type, None)

Pattern 4: Safe Text Input def set_text_safely(obj: 'Atspi.Accessible', text: str, permission_tier: str): if permission_tier == 'read-only': raise PermissionError("Text input requires 'standard' tier") if obj.get_role() == Atspi.Role.PASSWORD_TEXT: raise SecurityError("Cannot input to password fields")

editable = obj.get_editable_text()
text_iface = obj.get_text()
editable.delete_text(0, text_iface.get_character_count())
editable.insert_text(0, text, len(text))
  1. Implementation Workflow (TDD) Step 1: Write Failing Test First

tests/test_atspi_automation.py

import pytest from unittest.mock import Mock, patch

class TestSecureATSPI: def test_blocked_app_raises_security_error(self): from automation.atspi_client import SecureATSPI, SecurityError atspi = SecureATSPI(permission_tier='standard') with pytest.raises(SecurityError, match="blocked"): atspi.get_application('keepassxc')

def test_password_field_access_blocked(self):
    from automation.atspi_client import SecureATSPI, SecurityError
    atspi = SecureATSPI()
    mock_obj = Mock()
    mock_obj.get_role.return_value = 24  # PASSWORD_TEXT
    with pytest.raises(SecurityError):
        atspi.get_object_value(mock_obj)

def test_read_only_tier_blocks_actions(self):
    from automation.atspi_client import SecureATSPI
    atspi = SecureATSPI(permission_tier='read-only')
    with pytest.raises(PermissionError):
        atspi.perform_action(Mock(), 'click')

Step 2: Implement Minimum to Pass

Implement the security checks and validations to pass tests.

Step 3: Refactor Following Patterns

Apply caching, async patterns, and connection pooling.

Step 4: Run Full Verification

Run all tests with coverage

pytest tests/ -v --cov=automation --cov-report=term-missing

Run security-specific tests

pytest tests/ -k "security or blocked" -v

Verify no password field access

pytest tests/ -k "password" -v

  1. Performance Patterns Pattern 1: Event Filtering (Reduce D-Bus Traffic)

BAD: Register for all events

Atspi.EventListener.register_full(handler, 'object:', None)

GOOD: Filter to specific events needed

ALLOWED_EVENTS = ['object:state-changed:focused', 'window:activate'] for event in ALLOWED_EVENTS: Atspi.EventListener.register_full(handler, event, None)

Pattern 2: Node Caching (Avoid Repeated Lookups)

BAD: Re-traverse tree for each query

def find_button(): desktop = Atspi.get_desktop(0) for i in range(desktop.get_child_count()): app = desktop.get_child_at_index(i) # Full tree traversal every time

GOOD: Cache frequently accessed nodes

class CachedATSPI: def init(self): self._app_cache = {} self._cache_ttl = 5.0 # seconds

def get_application(self, name: str):
    now = time.time()
    if name in self._app_cache:
        cached, timestamp = self._app_cache[name]
        if now - timestamp < self._cache_ttl:
            return cached

    app = self._find_app(name)
    self._app_cache[name] = (app, now)
    return app

Pattern 3: Async Queries (Non-Blocking Operations)

BAD: Blocking synchronous calls in main thread

buttons = [c for c in children if c.get_role() == PUSH_BUTTON]

GOOD: Use executor for heavy tree traversals

async def get_all_buttons_async(app): loop = asyncio.get_event_loop() return await loop.run_in_executor(None, lambda: find_buttons(app))

Pattern 4: Connection Pooling (Singleton)

BAD: Atspi.init() called per operation

GOOD: Singleton manager

class ATSPIManager: _instance = None def new(cls): if not cls._instance: cls._instance = super().new(cls) Atspi.init() return cls._instance

Pattern 5: Scope Limiting (Reduce Search Space)

BAD: Search entire desktop tree

result = search_recursive(Atspi.get_desktop(0), name)

GOOD: Limit to specific app

app = get_application(app_name) result = search_recursive(app, name)

BETTER: Add role filtering

result = search_with_role(app, name, role=Atspi.Role.PUSH_BUTTON)

  1. Security Standards 8.1 Critical Vulnerabilities Vulnerability Severity Mitigation AT-SPI2 Registry Bypass (CWE-284) HIGH Validate through registry D-Bus Session Hijacking (CVE-2022-42012) HIGH Validate D-Bus peer credentials Password Field Access (CWE-200) CRITICAL Block PASSWORD_TEXT role Input Injection (CWE-74) HIGH Application blocklists Event Flooding (CWE-400) MEDIUM Rate limiting, event filtering 8.2 Permission Tier Model PERMISSION_TIERS = { 'read-only': { 'allowed_operations': ['get_name', 'get_role', 'get_state', 'find'], 'blocked_roles': [Atspi.Role.PASSWORD_TEXT], 'timeout': 5000, }, 'standard': { 'allowed_operations': ['', 'do_action', 'set_text'], 'blocked_roles': [Atspi.Role.PASSWORD_TEXT], 'timeout': 10000, }, 'elevated': { 'allowed_operations': [''], 'blocked_apps': ['polkit', 'gnome-keyring'], 'timeout': 30000, } }

  2. Common Mistakes Never: Access Password Fields

BAD: No role check

value = obj.get_text().get_text(0, -1)

GOOD: Check role first

if obj.get_role() != Atspi.Role.PASSWORD_TEXT: value = obj.get_text().get_text(0, -1)

Never: Skip Application Validation

BAD: Direct access

app = desktop.get_child_at_index(0) interact(app)

GOOD: Validate first

if is_allowed_app(app.get_name()): interact(app)

  1. Pre-Implementation Checklist Phase 1: Before Writing Code Reviewed AT-SPI2 security patterns in this skill Identified target applications and verified not in blocklist Determined required permission tier (read-only/standard/elevated) Wrote failing tests for security validations Planned caching strategy for node lookups Phase 2: During Implementation Implemented application blocklist checks Added PASSWORD_TEXT role blocking Enforced timeouts on all D-Bus calls Applied node caching for performance Used event filtering (not wildcard subscriptions) Implemented scope limiting for searches Phase 3: Before Committing All pytest tests pass with coverage > 80% Audit logging verified for all operations Rate limiting tested under load No security warnings in test output Performance verified (< 100ms for element lookups)
  2. Summary

Your goal is to create AT-SPI2 automation that is:

Secure: Application validation, role blocking, audit logging Reliable: Timeout enforcement, error handling Accessible: Respects assistive technology boundaries

Security Reminders:

Always block access to PASSWORD_TEXT roles Validate applications before automation Enforce timeouts on all D-Bus calls Log all operations for audit Use appropriate permission tiers References See references/security-examples.md See references/threat-model.md See references/advanced-patterns.md

返回排行榜