converter

package
v1.6.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 17, 2026 License: Apache-2.0 Imports: 29 Imported by: 0

Documentation

Overview

Package converter provides functionality to convert device configurations to various formats.

Package converter provides functionality to convert device configurations to markdown.

Package converter provides functionality to convert device configurations to various formats.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrUnsupportedFormat is returned when an unsupported output format is requested.
	ErrUnsupportedFormat = errors.New("unsupported format")

	// ErrNilDevice is returned when the input device configuration is nil.
	ErrNilDevice = errors.New("device configuration is nil")
)

Sentinel errors returned by the converter package.

View Source
var DefaultRegistry = newDefaultRegistry() //nolint:gochecknoglobals // package-level singleton

DefaultRegistry is the package-level registry pre-populated with all built-in format handlers. It is the single source of truth for supported formats.

View Source
var ErrInvalidWrapWidth = errors.New("wrap width must be -1 (auto-detect), 0 (no wrapping), or positive")

ErrInvalidWrapWidth indicates that the wrap width setting is invalid.

Functions

func EnrichForExport added in v1.6.0

func EnrichForExport(data *common.CommonDevice)

EnrichForExport populates the read-only enrichment fields on data in place when they are nil: DeviceType (defaulting to OPNsense), Statistics, Analysis, SecurityAssessment, and PerformanceMetrics. ComplianceResults is left alone — it is populated externally by the audit handler.

EnrichForExport is the explicit memoization entry point for callers preparing the same device for multiple format exports (e.g. JSON + YAML + Markdown). analysis.ComputeStatistics and analysis.ComputeAnalysis are linear-or-worse in the number of interfaces, rules, and services and dominate per-format export time; calling EnrichForExport once before the format loop avoids recomputing them per format. Subsequent prepareForExport calls reuse the populated fields and skip the heavy work.

SECURITY: EnrichForExport does not redact sensitive fields. The resulting *CommonDevice carries plaintext secrets — most notably the SNMP community string in Statistics.ServiceDetails — because analysis.ComputeStatistics observes unredacted input by design (presence checks must see real values). Callers MUST NOT marshal or log the device directly after EnrichForExport. Always pass the device through prepareForExport (or a downstream Generator that calls prepareForExport) so the redact branch can produce a clone with the sensitive fields stripped.

Redaction is per-export and is applied by prepareForExport on its shallow copy. The Statistics pointer produced here is reused by every subsequent prepareForExport call — the redact-path clones the Statistics struct before mutating ServiceDetails so a pre-enriched device is safe to share across redact=true and redact=false callers.

CACHE INVALIDATION: EnrichForExport memoizes Statistics and Analysis as a snapshot of the device at call time. If the caller mutates a field that feeds those computations (e.g., device.SNMP.ROCommunity, FirewallRules, Interfaces) after calling EnrichForExport, the cached values go stale and subsequent exports will reflect the pre-mutation state. Re-call EnrichForExport after clearing the affected enrichment field when the underlying configuration changes between exports.

Clearing Statistics is sufficient to invalidate the Statistics-derived fields too: SecurityAssessment and PerformanceMetrics are recomputed together with Statistics. To refresh Analysis, clear Analysis. The two caches are independent.

EnrichForExport is not safe for concurrent use on the same *CommonDevice. Callers preparing one device for parallel format exports must call EnrichForExport once before fanning out.

EnrichForExport on a nil *CommonDevice is a documented no-op. Note that the downstream prepareForExport will still panic on nil; callers must guard nil at their own boundary (the JSONConverter / YAMLConverter wrappers and HybridGenerator.Generate already do).

NOTE: analysis.ComputeStatistics and analysis.ComputeAnalysis intentionally receive the unredacted data so that presence checks (e.g., "is SNMP configured?") see real values.

func RenderMarkdown added in v1.4.0

func RenderMarkdown(content string) (string, error)

RenderMarkdown parses and renders markdown content to HTML using goldmark with extended features (GFM, definition lists, emoji, footnotes). Returns the rendered HTML string or an error if rendering fails. Raw HTML tags (e.g., <details>, <summary>) are preserved in the output.

func RenderMarkdownToHTML added in v1.3.0

func RenderMarkdownToHTML(md string) (string, error)

RenderMarkdownToHTML converts markdown content to a self-contained HTML document. It uses goldmark for markdown-to-HTML conversion, transforms GitHub-style alert blockquotes into styled div elements, and wraps the result in htmlShell.

func RunConverterTests

func RunConverterTests(
	t *testing.T,
	tests []TestCase,
	convertFunc func(context.Context, *common.CommonDevice) (string, error),
)

RunConverterTests runs the standard converter test suite.

func RunNewFieldsSerializationTests added in v1.3.0

func RunNewFieldsSerializationTests(t *testing.T)

RunNewFieldsSerializationTests verifies that all new CommonDevice fields appear in both JSON and YAML serialization output and that sensitive data is redacted.

func StripMarkdownFormatting added in v1.3.0

func StripMarkdownFormatting(markdown string) (string, error)

StripMarkdownFormatting converts markdown to plain text using a goldmark -> HTML -> html2text pipeline. The goldmark renderer (shared with HTML output) handles all markdown parsing, while html2text provides proper HTML-to-text conversion using Go's net/html parser.

Tables and alerts are extracted from the HTML before html2text processing (using placeholders) because html2text doesn't handle table layout or preserve the tab-separated formatting we need.

func ValidateMarkdown added in v1.4.0

func ValidateMarkdown(content string) error

ValidateMarkdown checks if the provided markdown content is syntactically valid. It returns an error if the content cannot be parsed as markdown.

Types

type Adapter

type Adapter interface {
	Converter
	SetOptions(opts any)
	GetOptions() any
}

Adapter represents the interface for adapters that bridge between old and new converter implementations.

type Converter

type Converter interface {
	ToMarkdown(ctx context.Context, data *common.CommonDevice) (string, error)
}

Converter is the interface for converting device configurations to markdown.

type Format added in v1.1.0

type Format string

Format represents the output format type.

const (
	// FormatMarkdown represents markdown output format.
	FormatMarkdown Format = "markdown"
	// FormatJSON represents JSON output format.
	FormatJSON Format = "json"
	// FormatYAML represents YAML output format.
	FormatYAML Format = "yaml"
	// FormatText represents plain text output format (markdown with formatting stripped).
	FormatText Format = "text"
	// FormatHTML represents self-contained HTML output format.
	FormatHTML Format = "html"
)

Supported output format constants for report generation.

func (Format) String added in v1.1.0

func (f Format) String() string

String returns the string representation of the format.

func (Format) Validate added in v1.1.0

func (f Format) Validate() error

Validate checks if the format is supported by looking it up in the DefaultRegistry.

type FormatHandler added in v1.3.0

type FormatHandler interface {
	// FileExtension returns the file extension for this format (e.g., ".md", ".json").
	FileExtension() string

	// Aliases returns alternative names for this format (e.g., "md" for markdown).
	Aliases() []string

	// Generate creates documentation as a string using the provided generator context.
	// The ctx is threaded to per-subsystem boundary checks inside each format's
	// generator (e.g., between report body and audit section for markdown).
	Generate(ctx context.Context, g *HybridGenerator, data *common.CommonDevice, opts Options) (string, error)

	// GenerateToWriter writes documentation directly to the provided io.Writer.
	// The ctx is threaded to per-subsystem boundary checks inside each format's
	// generator.
	GenerateToWriter(
		ctx context.Context,
		g *HybridGenerator,
		w io.Writer,
		data *common.CommonDevice,
		opts Options,
	) error
}

FormatHandler defines the interface for format-specific generation logic. Each handler encapsulates the generation, streaming, and metadata for a single output format, allowing the FormatRegistry to dispatch by format name.

type FormatRegistry added in v1.3.0

type FormatRegistry struct {
	// contains filtered or unexported fields
}

FormatRegistry centralises format dispatch by mapping canonical format names and aliases to FormatHandler implementations. It replaces scattered switch statements with a single source of truth for supported formats.

func NewFormatRegistry added in v1.3.0

func NewFormatRegistry() *FormatRegistry

NewFormatRegistry creates an empty FormatRegistry.

func (*FormatRegistry) Canonical added in v1.3.0

func (r *FormatRegistry) Canonical(format string) (string, bool)

Canonical returns the canonical format name for the given format string, resolving aliases. The boolean indicates whether the format was recognized. When ok is false, the returned string is the lowercased input (unresolved).

func (*FormatRegistry) Extensions added in v1.3.0

func (r *FormatRegistry) Extensions() map[string]string

Extensions returns a map of canonical format name to file extension.

func (*FormatRegistry) Get added in v1.3.0

func (r *FormatRegistry) Get(format string) (FormatHandler, error)

Get returns the handler for the given format name (canonical or alias). Returns ErrUnsupportedFormat if no handler matches.

func (*FormatRegistry) Register added in v1.3.0

func (r *FormatRegistry) Register(format string, handler FormatHandler)

Register adds a handler for the given canonical format name. It also registers all aliases returned by handler.Aliases(). Panics on duplicate registration, consistent with the database/sql driver pattern.

func (*FormatRegistry) ValidFormats added in v1.3.0

func (r *FormatRegistry) ValidFormats() []string

ValidFormats returns a sorted slice of canonical format names.

func (*FormatRegistry) ValidFormatsWithAliases added in v1.3.0

func (r *FormatRegistry) ValidFormatsWithAliases() []string

ValidFormatsWithAliases returns a sorted slice of all accepted format strings, including both canonical names and aliases.

type Generator added in v1.1.0

type Generator interface {
	// Generate creates documentation in a specified format from the provided device configuration.
	// This method returns the complete output as a string, which is useful when the output
	// needs further processing (e.g., HTML conversion).
	Generate(ctx context.Context, cfg *common.CommonDevice, opts Options) (string, error)
}

Generator interface for creating documentation in various formats.

func NewMarkdownGenerator added in v1.1.0

func NewMarkdownGenerator(logger *logging.Logger, _ Options) (Generator, error)

NewMarkdownGenerator creates a HybridGenerator configured with a MarkdownBuilder and the provided logger. Despite its name, the returned Generator supports all output formats (Markdown, JSON, YAML, Text, HTML) via the Options passed to Generate(). The opts parameter is ignored and exists for backward compatibility. Returns an error only if the provided logger is nil and creating a default logger fails.

type HybridGenerator added in v1.1.0

type HybridGenerator struct {
	// contains filtered or unexported fields
}

HybridGenerator provides programmatic markdown, JSON, and YAML generation. It uses the builder pattern for markdown output and direct serialization for JSON/YAML.

HybridGenerator implements both Generator (string-based) and StreamingGenerator (io.Writer-based) interfaces. Use GenerateToWriter for memory-efficient streaming output, or Generate when you need the output as a string for further processing.

func NewHybridGenerator added in v1.1.0

func NewHybridGenerator(reportBuilder builder.ReportBuilder, logger *logging.Logger) (*HybridGenerator, error)

NewHybridGenerator creates a HybridGenerator that uses the provided ReportBuilder and logger. If logger is nil, NewHybridGenerator creates a default logger and returns an error if logger creation fails.

func (*HybridGenerator) Generate added in v1.1.0

func (g *HybridGenerator) Generate(ctx context.Context, data *common.CommonDevice, opts Options) (string, error)

Generate creates documentation in the specified format from the provided OPNsense configuration. Supported formats: markdown (default), json, yaml, text, and html.

Memory tradeoff (JSON/YAML): Generate pays roughly 2x peak memory for JSON and YAML output because the marshaled byte slice and its string(...) conversion both live on the heap simultaneously. For markdown, text, and HTML the builder already accumulates a string, so there is no additional penalty versus GenerateToWriter. Prefer GenerateToWriter once output approaches ~5MB.

Use Generate when:

  • You need the result as an in-memory string (to embed in another structure, pass to a templating system, return from an API handler, or display in a TUI).
  • The caller does not have an io.Writer to hand off (no file handle, no http.ResponseWriter, no buffer already in scope).
  • Output is small and the ergonomics of a return value matter more than peak memory.

For streaming output, writing directly to a file/socket/HTTP response, or composing with io.Copy / io.MultiWriter, see GenerateToWriter.

func (*HybridGenerator) GenerateToWriter added in v1.1.0

func (g *HybridGenerator) GenerateToWriter(
	ctx context.Context,
	w io.Writer,
	data *common.CommonDevice,
	opts Options,
) error

GenerateToWriter writes documentation directly to the provided io.Writer.

Supported formats: markdown (default), json, yaml, text, and html. For markdown, sections are written incrementally as they are generated. For JSON and YAML, an encoder writes directly to w — this avoids the 2x peak-memory hit that Generate incurs (marshaled bytes plus their string(...) conversion both resident at once). For text and HTML, the full output is produced then written because those formats require complete document serialization or post-processing.

Use GenerateToWriter when:

  • You are writing directly to a file, socket, or HTTP response.
  • Output may be large (>5MB for JSON/YAML) and peak memory matters.
  • You want partial-output-on-error semantics: bytes already flushed to w remain visible if encoding fails partway through.
  • You are composing with io.Copy, io.MultiWriter, or other writer patterns.

For an in-memory string — for example to embed in another structure, feed a templating system, or return from an API handler — see Generate.

func (*HybridGenerator) GetBuilder added in v1.1.0

func (g *HybridGenerator) GetBuilder() builder.ReportBuilder

GetBuilder returns the current report builder as a ReportBuilder. The underlying value is typically a ReportBuilder (e.g., *MarkdownBuilder) because SetBuilder and NewHybridGenerator accept ReportBuilder. Returns nil if the builder is nil or does not satisfy the full ReportBuilder interface.

func (*HybridGenerator) SetBuilder added in v1.1.0

func (g *HybridGenerator) SetBuilder(reportBuilder builder.ReportBuilder)

SetBuilder sets the report builder for programmatic generation.

type JSONConverter

type JSONConverter struct{}

JSONConverter is a JSON converter for device configurations.

func NewJSONConverter

func NewJSONConverter() *JSONConverter

NewJSONConverter creates and returns a new JSONConverter for converting device configurations to JSON format.

func (*JSONConverter) ToJSON

func (c *JSONConverter) ToJSON(_ context.Context, data *common.CommonDevice, redact bool) (string, error)

ToJSON converts a device configuration to JSON. When redact is true, sensitive fields (passwords, private keys, community strings) are replaced with [REDACTED] in the output.

type MarkdownConverter

type MarkdownConverter struct{}

MarkdownConverter is a markdown converter for device configurations.

func NewMarkdownConverter

func NewMarkdownConverter() *MarkdownConverter

NewMarkdownConverter creates and returns a new MarkdownConverter for converting device configuration data to markdown format.

func (*MarkdownConverter) ToMarkdown

func (c *MarkdownConverter) ToMarkdown(_ context.Context, data *common.CommonDevice) (string, error)

ToMarkdown converts a device configuration to markdown.

type Options added in v1.1.0

type Options struct {
	// Format specifies the output format (markdown, json, yaml, text, html).
	Format Format

	// Comprehensive specifies whether to generate a comprehensive report.
	Comprehensive bool

	// Sections specifies which configuration sections to include.
	Sections []string

	// Theme specifies the terminal rendering theme for markdown output.
	Theme Theme

	// WrapWidth specifies the column width for text wrapping.
	WrapWidth int

	// EnableTables controls whether to render data as tables.
	EnableTables bool

	// EnableColors controls whether to use colored output.
	EnableColors bool

	// EnableEmojis controls whether to include emoji icons in output.
	EnableEmojis bool

	// Compact controls whether to use a more compact output format.
	Compact bool

	// IncludeMetadata controls whether to include generation metadata.
	IncludeMetadata bool

	// SuppressWarnings suppresses non-critical warnings.
	SuppressWarnings bool

	// IncludeTunables controls whether all system tunables are included in the output.
	// When false (default), only security-related tunables are shown in markdown, text, and HTML output.
	// JSON and YAML exports always include all tunables regardless of this setting.
	IncludeTunables bool

	// FailuresOnly filters the plugin control results table to show only non-compliant controls.
	// Only meaningful in blue mode audit reports where compliance checks are executed.
	FailuresOnly bool

	// Redact controls whether sensitive fields (passwords, private keys, community strings, etc.)
	// are replaced with [REDACTED] in the output. Defaults to false.
	Redact bool
}

Options contains configuration options for report generation.

func DefaultOptions added in v1.1.0

func DefaultOptions() Options

DefaultOptions returns an Options initialized with the package's default settings for report generation. Defaults: Format=markdown, Theme=auto, WrapWidth=0, EnableTables=true, EnableColors=true, EnableEmojis=true, IncludeMetadata=true, IncludeTunables=false, Comprehensive and Compact set to false, and SuppressWarnings set to false.

func (Options) Validate added in v1.1.0

func (o Options) Validate() error

Validate checks if the options are valid.

func (Options) WithColors added in v1.1.0

func (o Options) WithColors(enabled bool) Options

WithColors enables or disables colored output.

func (Options) WithCompact added in v1.1.0

func (o Options) WithCompact(compact bool) Options

WithCompact enables or disables compact output format.

func (Options) WithComprehensive added in v1.1.0

func (o Options) WithComprehensive(enabled bool) Options

WithComprehensive enables or disables comprehensive report generation.

func (Options) WithEmojis added in v1.1.0

func (o Options) WithEmojis(enabled bool) Options

WithEmojis enables or disables emoji icons.

func (Options) WithFailuresOnly added in v1.4.0

func (o Options) WithFailuresOnly(enabled bool) Options

WithFailuresOnly enables or disables filtering plugin control results to show only failures.

func (Options) WithFormat added in v1.1.0

func (o Options) WithFormat(format Format) Options

WithFormat sets the output format. Format validity is checked by Options.Validate().

func (Options) WithIncludeTunables added in v1.3.0

func (o Options) WithIncludeTunables(enabled bool) Options

WithIncludeTunables enables or disables inclusion of all system tunables. When false, only security-related tunables are shown in reports.

func (Options) WithMetadata added in v1.1.0

func (o Options) WithMetadata(enabled bool) Options

WithMetadata enables or disables generation metadata.

func (Options) WithRedact added in v1.3.0

func (o Options) WithRedact(redact bool) Options

WithRedact enables or disables sensitive field redaction.

func (Options) WithSections added in v1.1.0

func (o Options) WithSections(sections ...string) Options

WithSections sets the sections to include in output.

func (Options) WithSuppressWarnings added in v1.1.0

func (o Options) WithSuppressWarnings(suppress bool) Options

WithSuppressWarnings enables or disables warning suppression.

func (Options) WithTables added in v1.1.0

func (o Options) WithTables(enabled bool) Options

WithTables enables or disables table rendering.

func (Options) WithTheme added in v1.1.0

func (o Options) WithTheme(theme Theme) Options

WithTheme sets the terminal rendering theme.

func (Options) WithWrapWidth added in v1.1.0

func (o Options) WithWrapWidth(width int) Options

WithWrapWidth sets the text wrapping width.

type StreamingGenerator added in v1.1.0

type StreamingGenerator interface {
	Generator

	// GenerateToWriter writes documentation directly to the provided io.Writer.
	// This is more memory-efficient than Generate() for large configurations
	// as it streams output section-by-section.
	GenerateToWriter(ctx context.Context, w io.Writer, cfg *common.CommonDevice, opts Options) error
}

StreamingGenerator extends Generator with io.Writer-based output support. This interface enables memory-efficient generation by writing directly to the destination without accumulating the entire output in memory first.

type TestCase

type TestCase struct {
	Name        string
	Data        *common.CommonDevice
	WantErr     bool
	ErrType     error
	ValidateOut func(t *testing.T, result string) // Function to validate the output format
}

TestCase represents a test case for converter tests.

func GetCommonTestCases

func GetCommonTestCases() []TestCase

GetCommonTestCases returns common test cases for both JSON and YAML converters.

type Theme added in v1.1.0

type Theme string

Theme represents the rendering theme for terminal output.

const (
	// ThemeAuto automatically detects the appropriate theme.
	ThemeAuto Theme = "auto"
	// ThemeDark uses a dark terminal theme.
	ThemeDark Theme = "dark"
	// ThemeLight uses a light terminal theme.
	ThemeLight Theme = "light"
	// ThemeNone disables styling for plain text output.
	ThemeNone Theme = "none"
)

Supported rendering theme constants for terminal output styling.

func (Theme) String added in v1.1.0

func (t Theme) String() string

String returns the string representation of the theme.

type YAMLConverter

type YAMLConverter struct{}

YAMLConverter is a YAML converter for device configurations.

func NewYAMLConverter

func NewYAMLConverter() *YAMLConverter

NewYAMLConverter creates and returns a new YAMLConverter for transforming device configurations to YAML format.

func (*YAMLConverter) ToYAML

func (c *YAMLConverter) ToYAML(_ context.Context, data *common.CommonDevice, redact bool) (string, error)

ToYAML converts a device configuration to YAML. When redact is true, sensitive fields (passwords, private keys, community strings) are replaced with [REDACTED] in the output.

Directories

Path Synopsis
Package builder provides programmatic report building functionality for device configurations.
Package builder provides programmatic report building functionality for device configurations.
Package formatters provides utility functions for formatting data in markdown reports.
Package formatters provides utility functions for formatting data in markdown reports.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL