pgadmin4/web/pgadmin/llm/reports/sections.py

388 lines
12 KiB
Python

##########################################################################
#
# pgAdmin 4 - PostgreSQL Tools
#
# Copyright (C) 2013 - 2026, The pgAdmin Development Team
# This software is released under the PostgreSQL Licence
#
##########################################################################
"""Section definitions for report generation pipeline.
Each report type has a set of sections that can be analyzed independently.
Sections are mapped to SQL queries and have descriptions for LLM guidance.
"""
from pgadmin.llm.reports.models import Section
# =============================================================================
# SECURITY REPORT SECTIONS
# =============================================================================
SECURITY_SECTIONS = [
Section(
id='authentication',
name='Authentication Configuration',
description=(
'Password policies, SSL/TLS settings, authentication methods, '
'and connection security settings.'
),
queries=['security_settings', 'hba_rules'],
scope=['server']
),
Section(
id='access_control',
name='Access Control & Roles',
description=(
'Superuser accounts, privileged roles, login roles, '
'and role privilege assignments.'
),
queries=['superusers', 'privileged_roles', 'roles_no_expiry'],
scope=['server', 'database']
),
Section(
id='network_security',
name='Network Security',
description=(
'Network exposure settings, listen addresses, connection limits, '
'and pg_hba.conf rules.'
),
queries=['security_settings', 'hba_rules'],
scope=['server']
),
Section(
id='encryption',
name='Encryption & SSL',
description=(
'SSL/TLS configuration, password encryption method, '
'and data-at-rest encryption settings.'
),
queries=['security_settings'],
scope=['server']
),
Section(
id='object_permissions',
name='Object Permissions',
description=(
'Schema, table, and function access control lists (ACLs), '
'default privileges, and ownership.'
),
queries=['database_settings', 'schema_acls', 'table_acls',
'default_privileges'],
scope=['database']
),
Section(
id='rls_policies',
name='Row-Level Security',
description=(
'Row-level security policies, RLS-enabled tables, '
'and policy coverage analysis.'
),
queries=['rls_enabled_tables', 'rls_policies'],
scope=['database', 'schema']
),
Section(
id='security_definer',
name='Security Definer Functions',
description=(
'Functions running with elevated privileges (SECURITY DEFINER), '
'their ownership, and permissions.'
),
queries=['security_definer_functions'],
scope=['database', 'schema']
),
Section(
id='audit_logging',
name='Audit & Logging',
description=(
'Connection logging, statement logging, error logging, '
'and audit trail configuration.'
),
queries=['logging_settings'],
scope=['server']
),
Section(
id='extensions',
name='Extensions',
description=(
'Installed extensions and their security implications.'
),
queries=['extensions'],
scope=['server', 'database']
),
]
# =============================================================================
# PERFORMANCE REPORT SECTIONS
# =============================================================================
PERFORMANCE_SECTIONS = [
Section(
id='memory_config',
name='Memory Configuration',
description=(
'shared_buffers, work_mem, effective_cache_size, '
'maintenance_work_mem, and other memory settings.'
),
queries=['memory_settings'],
scope=['server']
),
Section(
id='checkpoint_wal',
name='Checkpoint & WAL',
description=(
'Checkpoint settings, WAL configuration, background writer stats, '
'and write-ahead log tuning.'
),
queries=['checkpoint_settings', 'wal_settings', 'bgwriter_stats'],
scope=['server']
),
Section(
id='autovacuum',
name='Autovacuum Configuration',
description=(
'Autovacuum settings, tables needing vacuum, '
'dead tuple accumulation, and maintenance status.'
),
queries=['autovacuum_settings', 'tables_needing_vacuum'],
scope=['server', 'database']
),
Section(
id='query_planner',
name='Query Planner Settings',
description=(
'Cost parameters, statistics targets, JIT compilation, '
'and planner optimization settings.'
),
queries=['planner_settings'],
scope=['server']
),
Section(
id='parallelism',
name='Parallelism & Workers',
description=(
'Parallel query configuration, worker processes, '
'and parallel maintenance settings.'
),
queries=['parallel_settings'],
scope=['server']
),
Section(
id='connection_pooling',
name='Connection Management',
description=(
'Max connections, reserved connections, timeouts, '
'and current connection status.'
),
queries=['connection_settings', 'active_connections'],
scope=['server']
),
Section(
id='cache_efficiency',
name='Cache Efficiency',
description=(
'Buffer cache hit ratios, database-level cache stats, '
'and table-level I/O patterns.'
),
queries=['database_stats', 'table_cache_stats'],
scope=['server', 'database']
),
Section(
id='index_usage',
name='Index Analysis',
description=(
'Index utilization, unused indexes, tables needing indexes, '
'and index size analysis.'
),
queries=['table_stats', 'unused_indexes', 'tables_needing_indexes',
'table_sizes'],
scope=['database']
),
Section(
id='slow_queries',
name='Query Performance',
description=(
'Slowest queries, most frequent queries, '
'and query execution statistics (requires pg_stat_statements).'
),
queries=['stat_statements_check', 'top_queries_by_time',
'top_queries_by_calls'],
scope=['server', 'database']
),
Section(
id='replication',
name='Replication Status',
description=(
'Replication lag, standby status, and WAL sender statistics.'
),
queries=['replication_status'],
scope=['server']
),
]
# =============================================================================
# DESIGN REPORT SECTIONS
# =============================================================================
DESIGN_SECTIONS = [
Section(
id='table_structure',
name='Table Structure',
description=(
'Table definitions, column counts, sizes, ownership, '
'and documentation coverage.'
),
queries=['tables_overview', 'columns_info'],
scope=['database', 'schema']
),
Section(
id='primary_keys',
name='Primary Key Analysis',
description=(
'Primary key design, tables without primary keys, '
'and key column choices.'
),
queries=['primary_keys', 'tables_without_pk'],
scope=['database', 'schema']
),
Section(
id='foreign_keys',
name='Referential Integrity',
description=(
'Foreign key relationships, orphan references, '
'and relationship coverage.'
),
queries=['foreign_keys'],
scope=['database', 'schema']
),
Section(
id='indexes',
name='Index Strategy',
description=(
'Index definitions, duplicate indexes, index types, '
'and coverage analysis.'
),
queries=['indexes_info', 'duplicate_indexes'],
scope=['database', 'schema']
),
Section(
id='constraints',
name='Constraints',
description=(
'Check constraints, unique constraints, '
'and data validation coverage.'
),
queries=['check_constraints', 'unique_constraints'],
scope=['database', 'schema']
),
Section(
id='normalization',
name='Normalization Analysis',
description=(
'Repeated column patterns, potential denormalization issues, '
'and data redundancy.'
),
queries=['repeated_column_names'],
scope=['database']
),
Section(
id='naming_conventions',
name='Naming Conventions',
description=(
'Table and column naming patterns, consistency analysis, '
'and naming standard compliance.'
),
queries=['object_names'],
scope=['database', 'schema']
),
Section(
id='data_types',
name='Data Type Review',
description=(
'Data type usage patterns, type consistency, '
'and type appropriateness.'
),
queries=['column_types'],
scope=['database']
),
]
# =============================================================================
# SECTION LOOKUPS
# =============================================================================
# Convert lists to dictionaries for quick lookup
SECURITY_SECTIONS_DICT = {s.id: s for s in SECURITY_SECTIONS}
PERFORMANCE_SECTIONS_DICT = {s.id: s for s in PERFORMANCE_SECTIONS}
DESIGN_SECTIONS_DICT = {s.id: s for s in DESIGN_SECTIONS}
# Combined lookup by report type
SECTIONS_BY_TYPE = {
'security': SECURITY_SECTIONS,
'performance': PERFORMANCE_SECTIONS,
'design': DESIGN_SECTIONS,
}
SECTIONS_DICT_BY_TYPE = {
'security': SECURITY_SECTIONS_DICT,
'performance': PERFORMANCE_SECTIONS_DICT,
'design': DESIGN_SECTIONS_DICT,
}
def get_sections_for_report(report_type: str) -> list[Section]:
"""Get all sections for a report type.
Args:
report_type: One of 'security', 'performance', 'design'.
Returns:
List of Section objects.
Raises:
ValueError: If report_type is invalid.
"""
sections = SECTIONS_BY_TYPE.get(report_type)
if sections is None:
raise ValueError(f"Invalid report type: {report_type}")
return sections
def get_sections_for_scope(
report_type: str,
scope: str
) -> list[Section]:
"""Get sections applicable to a specific scope.
Args:
report_type: One of 'security', 'performance', 'design'.
scope: One of 'server', 'database', 'schema'.
Returns:
List of Section objects applicable to the scope.
"""
all_sections = get_sections_for_report(report_type)
return [s for s in all_sections if scope in s.scope]
def get_section(report_type: str, section_id: str) -> Section:
"""Get a specific section by ID.
Args:
report_type: One of 'security', 'performance', 'design'.
section_id: The section identifier.
Returns:
Section object.
Raises:
ValueError: If section not found.
"""
sections_dict = SECTIONS_DICT_BY_TYPE.get(report_type, {})
section = sections_dict.get(section_id)
if section is None:
raise ValueError(
f"Section '{section_id}' not found in {report_type} report"
)
return section