Documents
Report Generation Architecture
Report Generation Architecture
Type
Topic
Status
Published
Created
Feb 27, 2026
Updated
Apr 19, 2026
Created by
Dosu Bot
Updated by
Dosu Bot

Report Generation Architecture#

The Report Generation Architecture in opnDossier is a multi-format export system that transforms OPNsense firewall configuration files into documentation and analysis reports. The convert command provides neutral configuration documentation, while the audit command supports two distinct report modes: Blue Team (defensive audit) and Red Team (attack surface analysis), each tailored to different operational perspectives. Unlike conventional template-based documentation generators, opnDossier employs programmatic generation via MarkdownBuilder, which uses direct method calls to the github.com/nao1215/markdown library for type-safe, compile-time validated markdown generation.

The architecture follows a three-tier design pattern separating concerns between formatting utilities (internal/converter/formatters/), report structure builders (internal/converter/builder/), and orchestration components (Generator interfaces). This separation enables the system to export to multiple formats (markdown, JSON, YAML, HTML, plaintext) while maintaining a single source of truth for configuration parsing and transformation. All report generation modules share common interfaces (ReportBuilder, Generator), the device-agnostic CommonDevice model, and the shared analysis package (internal/analysis/) for detection logic, statistics computation, and rule comparison.

The system is designed for offline-first, operator-focused workflows where exported files must be valid and parseable by standard tools. Smart file naming with overwrite protection ensures safe operation, with the -f flag available to force overwrites when needed.

Architecture Overview#

Design Philosophy#

The Report Generation Architecture embodies several key design principles:

  1. Programmatic over Template-Based: Uses direct Go method calls instead of text templates for markdown generation, providing type safety, compile-time validation, and enhanced maintainability
  2. Separation of Concerns: Clear boundaries between formatting logic, report structure, and orchestration
  3. Multi-Format Support: Single data processing pipeline serving multiple output formats
  4. Mode-Based Reporting: Two distinct audit modes (Blue/Red) with unified base generation and mode-specific augmentation

Data Processing Pipeline#

The system follows a four-stage data processing pipeline:

  1. XML Parsing: OPNsense config.xml files are parsed using Go's built-in encoding/xml package
  2. Data Conversion: Platform-specific XML DTOs are transformed into the device-agnostic CommonDevice model
  3. Report Generation: MarkdownBuilder programmatically generates markdown through method calls
  4. Output Rendering: Formatted output is rendered to terminal or exported to files

Three-Tier Architecture#

The converter package implements a layered architecture:

internal/
├── analysis/ # Shared analysis logic
│ ├── detect.go # Detection functions (dead rules, unused interfaces, security/performance/consistency issues)
│ ├── statistics.go # Statistics computation (ComputeStatistics, scoring)
│ ├── rules.go # Rule comparison (RulesEquivalent)
│ └── helpers.go # Shared helper functions
└── converter/
    ├── formatters/ # Tier 1: Pure formatting functions
    ├── builder/ # Tier 2: Report structure and assembly
    └── hybrid_generator.go # Tier 3: Multi-format orchestration

Shared Analysis Package

  • Detection logic: DetectDeadRules(), DetectUnusedInterfaces(), DetectSecurityIssues(), DetectPerformanceIssues(), DetectConsistency()
  • Statistics computation: ComputeStatistics(), ComputeSecurityScore(), ComputeConfigComplexity()
  • Rule comparison: RulesEquivalent() for duplicate detection
  • All exported functions include nil guards for defensive API safety
  • Used by both converter (for JSON/YAML export) and processor (for runtime analysis)
  • Uses typed enum constants (e.g., common.RuleTypeBlock, common.SeverityCritical) for type-safe comparisons

Tier 1: Formatting Utilities

  • Pure functions with no dependencies on report structure
  • Boolean formatting, timestamp conversion, markdown escaping
  • Security risk assessment and data transformations
  • Reusable across all report types and formats

Tier 2: Report Builders

  • Structure-aware report construction
  • Section assembly and table generation
  • Depends on Tier 1 formatters for display details
  • Implements ReportBuilder interface, which composes SectionBuilder, TableWriter, and ReportComposer sub-interfaces

Tier 3: Orchestration

  • Multi-format routing via FormatRegistry dispatch
  • Streaming and string-based output management
  • Implements Generator and StreamingGenerator interfaces
  • Uses handlerForFormat() registry lookups instead of switch statements

Core Components#

MarkdownBuilder#

The MarkdownBuilder is the primary report generation engine. It provides programmatic markdown generation through method-based composition. MarkdownBuilder implements all three sub-interfaces (SectionBuilder, TableWriter, ReportComposer) that compose the ReportBuilder interface, providing backward compatibility through interface composition.

The implementation is organized across domain-specific files in internal/converter/builder/:

  • builder.go: Core MarkdownBuilder struct, ReportBuilder composite interface (SectionBuilder + TableWriter + ReportComposer), and primary sections (system, network, security)
  • builder_vpn.go: VPN-related methods (IPsec, OpenVPN, VLAN, static routes, HA/CARP configuration)
  • builder_services.go: Services-related methods (DHCP, DNS, SNMP, NTP, load balancer monitors)

Structure:

type MarkdownBuilder struct {
    config *common.CommonDevice
    logger *logging.Logger
    generated time.Time
    toolVersion string
}

Key Characteristics:

Main Methods:

BuildStandardReport()

  • Generates neutral configuration documentation
  • Includes system, network, security, and services sections
  • Creates table of contents with navigation links

BuildComprehensiveReport()

  • Extended report with additional detail
  • Adds VPN (IPsec, OpenVPN), high availability, and IDS sections
  • Includes all Standard report content

Section Builders:

Table Generation:

All table methods accept a *markdown.Markdown instance and return it for method chaining:

Programmatic Generation Approach#

The MarkdownBuilder uses the github.com/nao1215/markdown library (v0.10.0) for fluent API-based markdown construction:

md := markdown.NewMarkdown(&buf).
    H1("OPNsense Configuration Summary").
    H2("System Information").
    PlainTextf("%s: %s", markdown.Bold("Hostname"), sys.Hostname).LF().
    PlainTextf("%s: %s", markdown.Bold("Domain"), sys.Domain).LF()

Benefits over Template-Based Generation:

  • Type Safety: Compile-time validation of markdown structure
  • Performance: No template parsing overhead, direct code execution
  • Composability: Methods can be chained and conditionally called
  • Maintainability: Pure Go code, no template language complexity
  • Testability: Direct unit testing of generation methods

Formatting Utilities (formatters/)#

The formatters package provides pure, stateless functions for data display and transformation:

formatters.go: Basic formatting

  • FormatBool(): Converts booleans to checkmark/x-mark
  • FormatBytes(): Human-readable byte sizes
  • FormatTimestamp(): ISO 8601 timestamp formatting
  • FormatInterfacesAsLinks(): Markdown links for interfaces

security.go: Security assessment

  • CalculateSecurityScore(): 0-100 security score calculation
  • AssessRiskLevel(): Severity to risk level mapping (emoji + text)
  • AssessServiceRisk(): Service-specific security risk evaluation
  • GroupServicesByStatus(): Running/stopped service grouping

transformers.go: Data transformations

  • FilterSystemTunables(): Sysctl filtering
  • Data aggregation and grouping utilities

utils.go: String utilities

  • EscapeTableContent(): Markdown special character escaping
  • String manipulation helpers

Generator Interfaces#

The system defines two complementary interfaces for report generation:

Generator Interface (String-based):

type Generator interface {
    Generate(ctx context.Context, cfg *common.CommonDevice, opts Options) (string, error)
}

StreamingGenerator Interface (Memory-efficient):

type StreamingGenerator interface {
    Generator
    GenerateToWriter(ctx context.Context, w io.Writer, cfg *common.CommonDevice, opts Options) error
}

The HybridGenerator implements both interfaces and coordinates multi-format output:

type HybridGenerator struct {
    builder reportGenerator // Narrowed interface (internal field)
    logger *logging.Logger
}

Interface Narrowing: Internally, HybridGenerator uses a narrower reportGenerator interface (composed of auditBuilder and ReportComposer) that exposes only the methods it directly calls: SetIncludeTunables, SetFailuresOnly, BuildAuditSection, BuildStandardReport, and BuildComprehensiveReport. The public API (SetBuilder/GetBuilder) continues to work with the full ReportBuilder interface for backward compatibility, with GetBuilder using a two-value type assertion to recover the full interface. This refactoring implements the Interface Segregation Principle (closed issue #323) with no breaking changes to existing code.

CommonDevice Model#

The CommonDevice struct in pkg/model/ provides a platform-agnostic device representation:

type CommonDevice struct {
    DeviceType DeviceType `json:"device_type" yaml:"device_type"`
    Version string `json:"version,omitempty" yaml:"version,omitempty"`
    System System `json:"system" yaml:"system,omitempty"`
    Interfaces []Interface `json:"interfaces,omitempty" yaml:"interfaces,omitempty"`
    FirewallRules []FirewallRule `json:"firewallRules,omitempty" yaml:"firewallRules,omitempty"`
    NAT NATConfig `json:"nat" yaml:"nat,omitempty"`
    VPN VPN `json:"vpn" yaml:"vpn,omitempty"`
    Routing Routing `json:"routing" yaml:"routing,omitempty"`
    ComplianceResults *ComplianceResults `json:"complianceResults,omitempty" yaml:"complianceResults,omitempty"`
}

This model serves as the single source of truth shared by:

  • All report generators (Blue and Red audit modes, plus convert command for neutral documentation)
  • All output formats (markdown, JSON, YAML, HTML, plaintext)
  • All formatters and transformation functions

The ComplianceResults field stores audit findings populated by handleAuditMode() before enrichment, enabling automatic serialization in JSON/YAML formats and programmatic rendering in markdown through BuildAuditSection().

ComplianceControl Model:

The ComplianceControl struct in pkg/model/enrichment.go includes a Status field populated during audit result mapping:

type ComplianceControl struct {
    ID string `json:"id,omitempty" yaml:"id,omitempty"`
    Status string `json:"status" yaml:"status"` // "PASS" or "FAIL"
    Title string `json:"title,omitempty" yaml:"title,omitempty"`
    Description string `json:"description,omitempty" yaml:"description,omitempty"`
    Category string `json:"category,omitempty" yaml:"category,omitempty"`
    Severity string `json:"severity,omitempty" yaml:"severity,omitempty"`
}

The Status field uses two constants defined in pkg/model/enrichment.go:

  • ControlStatusPass = "PASS" - Indicates a compliant control
  • ControlStatusFail = "FAIL" - Indicates a non-compliant control

This field is populated by the mapControls() function in cmd/audit_handler.go, which derives status from the plugin's Compliance map during audit result mapping. The self-describing status enables both structured JSON/YAML exports and markdown table rendering without re-deriving compliance state.

Type Safety with Typed Enums (PR #452): The CommonDevice model uses typed string enums for compile-time safety and to eliminate magic string literals. Key typed fields include:

  • FirewallRule.Type: Uses FirewallRuleType enum (RuleTypePass, RuleTypeBlock, RuleTypeReject)
  • FirewallRule.Direction: Uses FirewallDirection enum (DirectionIn, DirectionOut, DirectionAny)
  • FirewallRule.IPProtocol: Uses IPProtocol enum (IPProtocolInet, IPProtocolInet6)
  • NATConfig.OutboundMode: Uses NATOutboundMode enum (OutboundAutomatic, OutboundHybrid, OutboundAdvanced, OutboundDisabled)
  • LAGG.Protocol: Uses LAGGProtocol enum (LAGGProtocolLACP, LAGGProtocolFailover, LAGGProtocolLoadBalance, LAGGProtocolRoundRobin)
  • VirtualIP.Mode: Uses VIPMode enum (VIPModeCarp, VIPModeIPAlias, VIPModeProxyARP)

These typed enums provide compile-time validation of field values and prevent string typos. When JSON/YAML serialization is required, the enums automatically convert to their string representation. When aggregating statistics or using map keys, explicit casts to string are used (e.g., stats.RulesByType[string(rule.Type)]++).

Two Audit Modes#

The audit command provides two report modes with distinct purposes and audiences, orchestrated by the ModeController in internal/audit/mode_controller.go. Neutral configuration documentation is handled by the convert command, which does not run compliance checks or security analysis.

Architecture Pattern#

All modes share a unified generation process:

  1. Audit Analysis: ModeController runs compliance checks and generates an audit.Report
  2. Data Mapping: handleAuditMode() maps the audit results to device.ComplianceResults via mapAuditReportToComplianceResults()
  3. Standard Pipeline: Report generation is delegated to generateWithProgrammaticGenerator(), which flows through the standard HybridGenerator pipeline

This design eliminates format-specific code in cmd/audit_handler.go. All rendering logic lives in internal/converter/builder/, ensuring consistent audit section output across all formats (markdown, JSON, YAML).

Finding Data Structure#

Unified Type System (PR #391): As of PR #391, opnDossier uses a canonical Finding struct and Severity type defined in internal/analysis/, eliminating previous duplication across packages. The type hierarchy is:

  • analysis.Finding: Canonical finding struct in internal/analysis/finding.go
  • compliance.Finding: Type alias to analysis.Finding
  • processor.Finding: Type alias to analysis.Finding
  • audit.Finding: Embeds analysis.Finding and adds audit-specific fields (AttackSurface, ExploitNotes, Control)

All modules now use the same underlying structure, ensuring consistency across audit, compliance, and processor packages.

Finding Structure:

The analysis.Finding struct contains the following key fields:

  • Type: Category of the finding (e.g., "compliance", "security", "inventory"). Used for classification and rendering partitioning in BuildAuditSection(). Findings with Type: "inventory" are rendered in a separate "Configuration Notes" section rather than the main "Security Findings" table.
  • Severity: Severity level of the finding using analysis.Severity type ("critical", "high", "medium", "low", "info"). This field is displayed in report tables (except for inventory findings) and used for severity breakdowns.
  • Title: Short title of the finding
  • Description: Detailed description of the issue
  • Recommendation: Actionable remediation guidance
  • Component: Configuration component involved
  • Reference: Additional documentation links
  • References: Related standard or control identifiers
  • Tags: Classification labels
  • Metadata: Arbitrary key-value pairs for additional context

Severity Constants:

Severity levels are defined in internal/analysis/finding.go as constants:

  • analysis.SeverityCritical - Critical findings requiring immediate attention
  • analysis.SeverityHigh - High-severity findings to address soon
  • analysis.SeverityMedium - Medium-severity findings worth investigating
  • analysis.SeverityLow - Low-severity findings for general improvement
  • analysis.SeverityInfo - Informational findings with no immediate action required

All compliance plugins derive Severity from control metadata using the deriveSeverityFromControl() function, which resolves severity from the plugin's control definitions based on finding references. This ensures consistent severity classification across all plugins.

Blue Team Mode#

Purpose: Defensive security audit with compliance checks

Additional Content:

Unified Controls Table:

When plugin Control data is available, Blue Team reports render a unified controls table that includes both compliant and non-compliant controls with a Status column showing PASS or FAIL. This approach provides complete compliance reporting by showing all evaluated controls, not just failures. The --failures-only flag filters this table to show only non-compliant controls (Status=FAIL). When Control data is unavailable, the system falls back to the legacy findings-only table.

Per-Plugin Severity Breakdown:

Blue Team reports include granular severity statistics for each compliance plugin through the computePerPluginSummary() function. This function:

  • Calculates severity counts (critical/high/medium/low/info) for each plugin's findings using the shared countSeverities() helper
  • Uses analysis.Severity constants for consistent severity classification
  • Stores results in per-plugin ComplianceResult entries via the PluginFindings map
  • Enables appendAuditFindings() to render detailed severity breakdowns per plugin in the output report, including informational findings count ("Informational: N")

The severity counting logic is DRY (Don't Repeat Yourself) via the countSeverities() helper function, which tallies findings by severity level for both aggregate summaries and per-plugin breakdowns. This ensures consistency across all severity statistics in the report, with all severity values represented using the canonical analysis.Severity type.

Metadata: report_type: "blue_team"

Example Findings:

  • Insecure SNMP configurations (SNMPv1/v2c without community string protection)
  • Allow-all firewall rules without source/destination restrictions
  • Expired or expiring certificates
  • Missing or weak authentication on services

Usage:

opndossier audit config.xml --mode blue

# Show only failing controls in plugin results tables
opndossier audit config.xml --mode blue --failures-only

Red Team Mode#

Purpose: Attacker-focused reconnaissance and attack surface enumeration

Additional Content:

Metadata: report_type: "red_team", blackhat_mode: bool

Finding Structure: Includes AttackSurface and ExploitNotes fields specific to offensive security

Usage:

opndossier audit config.xml --mode red
opndossier audit config.xml --mode red --audit-blackhat # with commentary

Multi-Format Export#

Supported Formats#

The system exports to five output formats through a unified architecture:

  1. Markdown - Human-readable documentation (default)
  2. JSON - Machine-readable structured data
  3. YAML - Configuration management friendly
  4. HTML - Web browser viewing
  5. Plain Text - Terminal/email friendly

FormatRegistry Architecture#

The FormatRegistry serves as the single source of truth for supported output formats, replacing scattered constant definitions and switch statements across the codebase. All format-related operations—validation, alias resolution, file extension mapping, and generation dispatch—route through DefaultRegistry.

Key Components:

  • FormatHandler Interface: Defines Generate(), GenerateToWriter(), FileExtension(), and Aliases() methods that encapsulate format-specific logic
  • DefaultRegistry: Package-level singleton pre-populated with handlers for all five formats (markdown, json, yaml, text, html)
  • Alias Resolution: DefaultRegistry.Canonical() maps short aliases (md, yml, txt, htm) to canonical format names
  • Handler Dispatch: HybridGenerator.Generate() and GenerateToWriter() use handlerForFormat() for registry-based dispatch instead of switch statements

Adding New Formats:

To register a new output format, implement the FormatHandler interface and register it in newDefaultRegistry(). All validation, shell completion, file extension handling, and generation routing will automatically support the new format with no changes to caller code.

Related Documentation: See AGENTS.md §5.9b for detailed implementation guidance on the FormatRegistry pattern.

Format-Specific Processing#

Markdown Generation:

  • Uses MarkdownBuilder directly: Calls BuildStandardReport() or BuildComprehensiveReport()
  • Automatically appends BuildAuditSection() when ComplianceResults is present via HybridGenerator.generateMarkdown()
  • Programmatic method-based generation via nao1215/markdown library
  • Primary format with full feature support
  • Handler: markdownHandler with aliases ["md"] and extension .md

JSON/YAML Export:

  • Serializes CommonDevice directly via prepareForExport()
  • Delegates to analysis.ComputeStatistics() and analysis.ComputeAnalysis() for computed fields
  • ComplianceResults field serialized automatically via struct tags - no special handling needed
  • Supports redaction mode for sensitive fields
  • Dead rule findings include structured Kind field ("unreachable" or "duplicate") for classification
  • Handlers: jsonHandler (no aliases, .json) and yamlHandler (alias ["yml"], .yaml)

HTML Export:

  • Generates markdown first via MarkdownBuilder
  • Converts to HTML using goldmark library via RenderMarkdownToHTML()
  • Preserves tables, headers, and formatting
  • Handler: htmlHandler with aliases ["htm"] and extension .html

Plain Text Export:

  • Generates markdown first via MarkdownBuilder
  • Strips markdown formatting via StripMarkdownFormatting() for terminal output
  • Maintains structure and readability
  • Handler: textHandler with aliases ["txt"] and extension .txt

CLI Usage Examples#

# Export to JSON for scripting
opndossier convert config.xml --format json -o config.json

# Export to YAML for configuration management
opndossier convert config.xml --format yaml -o config.yaml

# Export to Markdown for documentation
opndossier convert config.xml --format markdown -o config.md

# Export to HTML for web viewing
opndossier convert config.xml --format html -o config.html

# Export to plain text for terminal/email
opndossier convert config.xml --format text -o config.txt

# Use format aliases (md, yml, txt, htm)
opndossier convert config.xml --format md -o config.md

# Export with redaction for sensitive data
opndossier convert config.xml --format json --redact -o config.json

Processor Integration#

The processor package supports all five output formats through integration with the converter's FormatRegistry:

  • Format Resolution: processor.Transform() uses DefaultRegistry.Canonical() to resolve format aliases before dispatching
  • Text Format: Generates markdown then calls converter.StripMarkdownFormatting() (exported function)
  • HTML Format: Generates markdown then calls converter.RenderMarkdownToHTML() (exported function)
  • JSON/YAML/Markdown: Native processor implementations via ToJSON(), toYAML(), and toMarkdown()
  • Alias Support: All standard aliases (md, yml, txt, htm) work consistently across converter and processor code paths

This unified approach ensures format aliases and validation rules remain consistent between the converter and processor packages, with the FormatRegistry as the single source of truth.

Redaction Support#

The redaction system replaces sensitive fields with [REDACTED] placeholders:

  • Pre-shared keys and passwords
  • SNMP community strings
  • API keys and tokens
  • Certificate private keys (Certificate.PrivateKey in the Certificates slice)
  • Certificate authority private keys (CertificateAuthority.PrivateKey in the CAs slice)
  • User password hashes

Implementation Details:

The redaction logic in internal/processor/report.go uses deep-copy behavior via redactedCopyUnsafe() to ensure the original CommonDevice structure remains unchanged during JSON/YAML serialization. Redaction is conditional—only entries with non-empty sensitive values are redacted. Helper functions hasCertPrivateKeys() and hasCAPrivateKeys() gate the redaction logic to avoid unnecessary processing when no sensitive data is present. Certificate and CA slices are deep-copied via make + copy before mutation to prevent unintended side effects.

See AGENTS.md §5.25 for expanded redaction implementation details.

Available in JSON and YAML formats via --redact flag.

Module Organization#

Directory Structure#

internal/
├── analysis/ # Shared analysis logic
│ ├── detect.go # Dead rule, unused interface, and issue detection
│ ├── statistics.go # Statistics computation and scoring
│ ├── rules.go # Rule comparison (RulesEquivalent)
│ ├── helpers.go # Shared helper functions (FindInterface, FindDHCPScope)
│ ├── detect_test.go # Detection tests
│ ├── statistics_test.go # Statistics computation tests
│ ├── rules_test.go # Rule comparison tests
│ └── helpers_test.go # Helper function tests
└── converter/
    ├── builder/ # Report construction layer
    │ ├── builder.go # MarkdownBuilder, ReportBuilder interface, core sections
    │ ├── builder_vpn.go # VPN-related builder methods (IPsec, OpenVPN, HA/CARP)
    │ ├── builder_services.go # Services-related builder methods (DHCP, DNS, SNMP, NTP)
    │ ├── writer.go # Streaming output support (SectionWriter)
    │ ├── helpers.go # Helper methods wrapping formatters
    │ └── errors.go # Builder-specific errors
    ├── formatters/ # Shared formatting utilities
    │ ├── formatters.go # Basic formatting (bool, bytes, timestamp)
    │ ├── security.go # Security scoring and risk assessment
    │ ├── transformers.go # Data filtering and aggregation
    │ └── utils.go # String escaping and manipulation
    ├── registry.go # FormatRegistry and FormatHandler interface
    ├── registry_test.go # Registry unit tests
    ├── hybrid_generator.go # Multi-format orchestration
    ├── options.go # Configuration options struct
    ├── enrichment.go # Export preparation and redaction
    ├── adapter.go # Legacy compatibility adapter
    ├── compat.go # Deprecated type aliases
    ├── errors.go # Package-level errors
    ├── markdown.go # Markdown converter (legacy)
    ├── json.go # JSON converter
    ├── yaml.go # YAML converter
    ├── html.go # HTML converter
    └── plaintext.go # Plain text converter

Dependency Relationships#

One-Way Dependencies:

builder/formatters/

  • Builder uses formatters for display details
  • Formatters have no knowledge of builder
  • Enables formatter reuse across packages

converter/analysis/

  • Converter delegates to analysis.ComputeStatistics() and analysis.ComputeAnalysis() for export enrichment
  • Analysis package has no knowledge of converter specifics
  • Enables shared detection logic between converter and processor

processor/analysis/

  • Processor delegates to analysis package for detection and statistics
  • Processor adds runtime-specific checks and context-aware reporting
  • Shared logic eliminates code duplication

Composition:

HybridGenerator contains reportGenerator

  • Generator delegates markdown generation to builder
  • Handles format routing and output management
  • Allows swapping builder implementations
  • Internal field uses narrowed reportGenerator interface (Interface Segregation Principle)
  • Public API maintains full ReportBuilder compatibility via type assertions

Shared vs. Report-Specific Code#

Shared Common Code:

Report-Specific Code:

Streaming Support#

SectionWriter Interface#

The SectionWriter interface enables memory-efficient streaming output:

type SectionWriter interface {
    WriteStandardReport(ctx context.Context, w io.Writer, data *common.CommonDevice) error
    WriteComprehensiveReport(ctx context.Context, w io.Writer, data *common.CommonDevice) error
    WriteSystemSection(ctx context.Context, w io.Writer, data *common.CommonDevice) error
    WriteNetworkSection(ctx context.Context, w io.Writer, data *common.CommonDevice) error
    WriteSecuritySection(ctx context.Context, w io.Writer, data *common.CommonDevice) error
    WriteServicesSection(ctx context.Context, w io.Writer, data *common.CommonDevice) error
    WriteAuditSection(w io.Writer, data *common.CommonDevice) error
}

Benefits#

Memory Efficiency:

  • Writes sections incrementally to output stream
  • Avoids loading entire report into memory
  • Suitable for large configurations

Streaming Integration:

  • Compatible with io.Writer interface
  • Can pipe directly to files, network sockets, or HTTP responses
  • Supports cancellation via context

Usage Pattern#

builder := builder.NewMarkdownBuilder(device, logger)
file, _ := os.Create("report.md")
defer file.Close()

err := builder.WriteStandardReport(ctx, file, device)

// Streaming audit section when compliance data is present
if device.ComplianceResults != nil {
    io.WriteString(file, "\n\n")
    err = builder.WriteAuditSection(file, device)
}

Pro-Level Generators#

Build Tag Architecture#

Report generators can be conditionally included using Go build tags:

//go:build pro

package reports

// Pro-level report generator

Build Variants#

Standard Builds:

  • Core report types (Blue and Red audit modes)
  • All essential functionality
  • Default build without special flags

Pro Builds:

  • Additional enterprise features
  • Advanced compliance frameworks
  • Built with -tags=pro

Custom Builds:

  • Specific report combinations
  • Feature subset selection
  • Custom build tag combinations

Future Modular Design#

As the system evolves, each report type may be extracted to its own package:

internal/converter/<report-type>/
├── generator.go # Main generation logic
├── calculations.go # Report-specific calculations
├── transformers.go # Data transformation functions
├── constants.go # Report-specific constants
└── <report-type>_test.go

What Remains Shared:

  • common.CommonDevice model
  • String helpers (markdown escaping, formatting)
  • Table builders (generic markdown table construction)
  • Common interfaces (ReportBuilder, Generator)

Usage Examples#

Basic Report Generation#

# Generate standard markdown report
opndossier convert config.xml

# Generate comprehensive report with all sections
opndossier convert config.xml --comprehensive

# Export to specific file
opndossier convert config.xml -o firewall-config.md

Mode-Based Reports#

# Blue team mode (defensive audit) - default
opndossier audit config.xml

# Blue team mode with specific plugins
opndossier audit config.xml --plugins stig,sans

# Show only failing controls in blue mode
opndossier audit config.xml --failures-only

# Red team mode (attack surface analysis)
opndossier audit config.xml --mode red --audit-blackhat

Multi-Format Export#

# JSON export for automation
opndossier convert config.xml --format json -o config.json

# YAML export with redaction
opndossier convert config.xml --format yaml --redact -o config.yaml

# HTML for web viewing
opndossier convert config.xml --format html -o config.html

Programmatic Usage#

import (
    "context"
    "github.com/EvilBit-Labs/opnDossier/internal/converter"
    "github.com/EvilBit-Labs/opnDossier/internal/converter/builder"
    common "github.com/EvilBit-Labs/opnDossier/pkg/model"
)

// Create builder
builder := builder.NewMarkdownBuilder(device, logger)

// Generate standard report
report, err := builder.BuildStandardReport(device)

// Generate comprehensive report
comprehensiveReport, err := builder.BuildComprehensiveReport(device)

// Use generator for multi-format support
gen := converter.NewHybridGenerator(logger)
opts := converter.Options{
    Format: "markdown",
    Comprehensive: true,
}
output, err := gen.Generate(ctx, device, opts)

// Example: Working with typed enums
rule := common.FirewallRule{
    Type: common.RuleTypePass, // Typed constant, not "pass"
    Direction: common.DirectionIn, // Typed constant, not "in"
    IPProtocol: common.IPProtocolInet, // Typed constant, not "inet"
    // ...
}

// Example: Filtering rules by type with typed enum
passRules := builder.FilterRulesByType(device.FirewallRules, common.RuleTypePass)

Relevant Code Files#

File PathDescriptionKey Components
internal/converter/builder/builder.goCore report builderMarkdownBuilder, ReportBuilder composite interface (SectionBuilder + TableWriter + ReportComposer), core section builders, table generators
internal/converter/builder/builder_vpn.goVPN builder methodsBuildIPsecSection, BuildOpenVPNSection, BuildHASection, writeIPsecSection, writeOpenVPNSection, writeVLANSection, writeStaticRoutesSection, writeHASection, VPN table builders with consistent markdown escaping
internal/converter/builder/builder_services.goServices builder methodsBuildServicesSection, writeServicesSection, WriteDHCPSummaryTable, WriteDHCPStaticLeasesTable, BuildDHCPSummaryTableSet, BuildDHCPStaticLeasesTableSet
internal/converter/builder/writer.goStreaming outputSectionWriter interface, streaming report methods
internal/converter/builder/helpers.goHelper methodsFormatter method wrappers, EscapePipeForMarkdown(), TruncateString(), FilterRulesByType() with typed enum parameter, convenience functions
internal/converter/formatters/formatters.goBasic formattingBoolean, timestamp, byte formatting functions
internal/converter/formatters/security.goSecurity utilitiesRisk assessment, security scoring, service risk evaluation
internal/converter/formatters/transformers.goData transformationFiltering, grouping, aggregation functions
internal/converter/formatters/utils.goString utilitiesMarkdown escaping, string manipulation
internal/converter/hybrid_generator.goMulti-format orchestrationGenerator interface, StreamingGenerator, HybridGenerator, handlerForFormat() registry lookup
internal/converter/registry.goFormat dispatchFormatRegistry, FormatHandler interface, DefaultRegistry singleton, format handlers for markdown/json/yaml/text/html
internal/converter/registry_test.goRegistry tests76 test cases covering Get, Canonical, Register, ValidFormats, Extensions, handler dispatch
internal/converter/options.goConfigurationOptions struct for report generation
internal/converter/enrichment.goData enrichmentExport preparation, redaction, delegates to analysis package for statistics and analysis
internal/analysis/detect.goDetection logicDead rule detection, unused interface detection, security/performance/consistency issue detection with typed enum constants
internal/analysis/statistics.goStatistics computationComputeStatistics, ComputeSecurityScore, ComputeConfigComplexity; aggregates enum values via string casts
internal/analysis/rules.goRule comparisonRulesEquivalent for duplicate detection, includes Disabled field comparison
internal/analysis/helpers.goHelper functionsFindInterface, FindDHCPScope, IndexedRule type
internal/analysis/finding.goCanonical finding typesFinding struct, Severity type, severity constants and validation helpers
internal/audit/mode_controller.goMode orchestrationModeController, mode-specific report generation, per-plugin severity breakdown
internal/audit/plugin.goPlugin registryPluginRegistry, compliance checks, severity derivation from control metadata
cmd/audit_handler.goCLI integrationhandleAuditMode(), mapAuditReportToComplianceResults(), audit report to CommonDevice mapping
internal/compliance/interfaces.goCompliance typesPlugin interface, Control struct, Finding type alias to analysis.Finding
internal/processor/processor.goProcessor logicProcess flow, Transform with FormatRegistry alias resolution, text/html format support
internal/processor/processor_test.goProcessor tests12 new tests for text/html formats and alias resolution (md/yml/txt/htm)
pkg/model/device.goData modelCommonDevice, platform-agnostic device representation, ComplianceResults field, typed enum constants (PR #452)
pkg/model/enrichment.goCompliance modelsComplianceResults, ComplianceFinding, PluginComplianceResult, ComplianceControl, ComplianceResultSummary
docs/development/architecture.mdArchitecture docsComprehensive design documentation
internal/converter/markdown_bench_test.goPerformance testsBenchmark tests for MarkdownBuilder

See Also#

Report Generation Architecture | Dosu