Skip to content

feat(converter): add streaming generation for large configurations - #189

Merged
unclesp1d3r merged 2 commits into
mainfrom
143-enhancement-consider-streaming-generation-for-large-configurations
Jan 29, 2026
Merged

feat(converter): add streaming generation for large configurations#189
unclesp1d3r merged 2 commits into
mainfrom
143-enhancement-consider-streaming-generation-for-large-configurations

Conversation

@unclesp1d3r

Copy link
Copy Markdown
Member

Summary

Changes

Streaming Generation (issue #143)

  • Add SectionWriter interface for io.Writer-based report generation
  • Add StreamingGenerator interface extending Generator with GenerateToWriter
  • Implement WriteStandardReport and WriteComprehensiveReport methods
  • Preserve string-based API for future HTML conversion workflows

Code Quality Improvements

  • Replace init() with sync.Once pattern for global registry
  • Add context cancellation support to XML parser
  • Use errors.Join() for proper error accumulation
  • Use slices.Sorted(maps.Keys()) for deterministic map iteration
  • Remove unnecessary runtime.GC() calls
  • Fix golangci-lint configuration conflict

Test plan

  • All existing tests pass
  • New writer tests added (writer_test.go)
  • just ci-check passes
  • Tested with production-size configs (1-5 MB)

Closes #143

🤖 Generated with Claude Code

unclesp1d3r and others added 2 commits January 29, 2026 00:22
- Remove forced runtime.GC() calls from XML parser (let Go manage GC)
- Add context cancellation support to parser for timeout handling
- Replace init() with sync.Once for global plugin registry initialization
- Use errors.Join() instead of chained %w error wrapping in convert cmd
- Sort map keys in report generation for deterministic output
- Simplify combineValidationErrors to use only strings.Builder
- Fix golangci-lint config conflict (gocyclo was both enabled/disabled)
- Run go mod tidy to remove unused dependencies

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implement Tier 1 streaming optimization for issue #143:

- Add SectionWriter interface for io.Writer-based report generation
- Add StreamingGenerator interface extending Generator
- Implement WriteStandardReport and WriteComprehensiveReport methods
- Add GenerateToWriter method to HybridGenerator
- Add generateToWriter infrastructure in convert.go for future use
- Preserve string-based API for HTML conversion workflows

This enables memory-efficient streaming output for large configurations
(1-5 MB production config.xml files) while maintaining compatibility
with the existing string-based API for further processing needs.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@unclesp1d3r unclesp1d3r linked an issue Jan 29, 2026 that may be closed by this pull request
@coderabbitai

coderabbitai Bot commented Jan 29, 2026

Copy link
Copy Markdown
Contributor

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added streaming output support for Markdown reports to enable efficient memory usage during report generation.
    • Added context cancellation support for XML parsing operations, enabling timeouts and cancellation of long-running parsing tasks.
  • Bug Fixes

    • Improved deterministic output by sorting map keys in reports for consistent, reproducible results.
  • Chores

    • Removed unused dependencies to reduce module footprint.
    • Updated linter configuration and refactored internal plugin registry initialization.

✏️ Tip: You can customize this high-level summary in your review settings.

Walkthrough

This PR implements streaming output generation for large OPNsense configurations to address memory efficiency concerns. It introduces a new SectionWriter interface and StreamingGenerator interface with corresponding implementations, adds context cancellation support to the XML parser, refactors error handling in the convert command, removes unused dependencies, and improves deterministic output through key sorting.

Changes

Cohort / File(s) Summary
Streaming Writer Infrastructure
internal/converter/builder/writer.go, internal/converter/builder/writer_test.go
Introduces SectionWriter interface and MarkdownBuilder streaming methods to write report sections directly to io.Writer. Implements WriteSystemSection, WriteNetworkSection, WriteSecuritySection, WriteServicesSection, and WriteStandardReport/WriteComprehensiveReport with header, TOC, and footer generation. Tests verify non-empty outputs and section content accuracy.
Streaming Generator Interface
internal/converter/hybrid_generator.go
Adds StreamingGenerator interface extending Generator with GenerateToWriter method. Implements writer-based generation paths for Markdown, JSON, and YAML formats with fallback to string-based generation. Routes context and writer to appropriate format handlers.
Parser Context Propagation
internal/parser/xml.go
Updates Parse method signature to use named context parameter (instead of _) and adds context cancellation checks in parsing loops. Removes forced runtime.GC() calls in decodeSection and decodeSysctl. Enables cancellation/timeout support for streaming XML parsing.
Convert Command Refactoring
cmd/convert.go
Refactors error collection to aggregate errors in a slice and return combined error via errors.Join instead of error chaining. Introduces new generateToWriter helper function for streaming output to io.Writer. Adds io import for writer support.
Deterministic Map Output
internal/processor/report.go
Adds sorted key iteration for Service.Details and statistics maps in addStatisticsList using maps.Keys and slices.Sorted to ensure reproducible Markdown output. Imports maps and slices standard library packages.
Plugin Registry Lazy Initialization
internal/audit/plugin.go
Replaces eager global registry initialization with lazy, thread-safe singleton via GetGlobalRegistry() function. Removes exported GlobalRegistry variable in favor of unexported globalRegistry and globalRegistryOnce. Updates all registry references to call GetGlobalRegistry().
Config String Building
internal/config/config.go
Simplifies combineValidationErrors by consolidating two separate string builders into single local sb variable. Maintains identical behavior while reducing variable overhead.
Linter Configuration
.golangci.yml
Disables gocyclo linter in favor of cyclop with descriptive comment in disabled section. No functional code changes.
Dependency Cleanup
go.mod
Removes 10 unused dependencies: sprig/v3, golang-lru/v2, mergo, goutils, semver/v3, uuid, xstrings, copystructure, reflectwalk, and decimal.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Client
    participant Parser as XML Parser
    participant Generator as HybridGenerator
    participant Writer as SectionWriter
    participant Output as io.Writer

    Client->>Parser: Parse(ctx, reader)
    Parser->>Parser: Check ctx.Done()
    Parser-->>Generator: OpnSenseDocument

    Client->>Generator: GenerateToWriter(ctx, writer, doc, opts)
    Generator->>Generator: Determine format (Markdown/JSON/YAML)
    
    alt Markdown Format
        Generator->>Writer: WriteStandardReport(writer, doc)
        Writer->>Output: WriteHeader()
        Writer->>Output: WriteTOC()
        Writer->>Output: WriteSystemSection()
        Writer->>Output: WriteNetworkSection()
        Writer->>Output: WriteSecuritySection()
        Writer->>Output: WriteServicesSection()
        Writer->>Output: WriteFooter()
    else JSON/YAML Format
        Generator->>Output: Marshal and write directly
    end

    Output-->>Client: Streamed output (low memory)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

type:feature, go, breaking_change, testing, dependencies, performance, priority:normal

Poem

🌊 Streaming flows where megabytes once gathered,
Section by section, no heap is battered,
Context cancels, maps sort true,
OPNsense configs now parse right through! 🚀

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 143-enhancement-consider-streaming-generation-for-large-configurations

Comment @coderabbitai help to get the list of available commands and usage tips.

@unclesp1d3r unclesp1d3r self-assigned this Jan 29, 2026
@codecov

codecov Bot commented Jan 29, 2026

Copy link
Copy Markdown

@unclesp1d3r
unclesp1d3r merged commit 16fa1bb into main Jan 29, 2026
12 of 17 checks passed
@unclesp1d3r
unclesp1d3r deleted the 143-enhancement-consider-streaming-generation-for-large-configurations branch January 29, 2026 06:02
@coderabbitai coderabbitai Bot added breaking_change Significant changes that disrupt backward compatibility. dependencies Pull requests that update a dependency file go Pull requests that update go code performance Performance optimization and improvements priority:normal Normal priority issue testing Test infrastructure and test-related issues type:feature New feature implementation labels Jan 29, 2026
unclesp1d3r added a commit that referenced this pull request Apr 19, 2026
…ocker snapshot, action pin

- Go version matrix in ci.yml test job: [stable, oldstable] with
  fail-fast: false; matches Go upstream support policy (N and N-1).
  Mergify required checks updated to 6 expanded names.
- CONTRIBUTING.md + README.md state the Go support policy explicitly.
- codecov.yml: raise project + patch targets from 70%/60% to 80%/80%
  (current total is 86.1%); add ignore: for testdata/, dist/. Mergify
  merge_protections wired with codecov/project + codecov/patch gates.
- Remove --skip=docker from goreleaser snapshot path in release.yml;
  GoReleaser --snapshot prevents registry pushes per docs; buildx
  already wired. Inline citation comment + updated snapshot summary
  to describe dockers_v2 platform-suffixed local tags.
- action.yml default version: "latest" -> "v1.4.0"; description
  actively recommends SHA pinning. latest remains valid (not rejected).
- README.md: sweep 3 GitHub Action examples from @main to @v1.4.0;
  drop stale "No release tags exist yet" comments; add new Pinning
  subsection (SHA pin recommended for production; tag pin acceptable;
  @main/@latest not recommended).
- RELEASING.md checklist items for future releases: bump action.yml
  default tag, sweep README usage examples, update SHA-pin example.
- SBOM job de-dup: ci.yml SBOM gated to push-to-main only; sbom.yml
  scheduled weekly and goreleaser release-time SBOMs unaffected.
- benchmarks.yml: replace ad-hoc `go install benchstat@latest` with
  `mise exec -- benchstat` (mise.toml pins benchstat).

Todos resolved: #119, #167, #168, #171, #172, #189.

Notes:
- Mergify `dependabot-workflows` queue still only requires `Lint`
  (workflow-only changes, intentional).

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
unclesp1d3r added a commit that referenced this pull request Apr 19, 2026
…ocker snapshot, action pin

- Go version matrix in ci.yml test job: [stable, oldstable] with
  fail-fast: false; matches Go upstream support policy (N and N-1).
  Mergify required checks updated to 6 expanded names.
- CONTRIBUTING.md + README.md state the Go support policy explicitly.
- codecov.yml: raise project + patch targets from 70%/60% to 80%/80%
  (current total is 86.1%); add ignore: for testdata/, dist/. Mergify
  merge_protections wired with codecov/project + codecov/patch gates.
- Remove --skip=docker from goreleaser snapshot path in release.yml;
  GoReleaser --snapshot prevents registry pushes per docs; buildx
  already wired. Inline citation comment + updated snapshot summary
  to describe dockers_v2 platform-suffixed local tags.
- action.yml default version: "latest" -> "v1.4.0"; description
  actively recommends SHA pinning. latest remains valid (not rejected).
- README.md: sweep 3 GitHub Action examples from @main to @v1.4.0;
  drop stale "No release tags exist yet" comments; add new Pinning
  subsection (SHA pin recommended for production; tag pin acceptable;
  @main/@latest not recommended).
- RELEASING.md checklist items for future releases: bump action.yml
  default tag, sweep README usage examples, update SHA-pin example.
- SBOM job de-dup: ci.yml SBOM gated to push-to-main only; sbom.yml
  scheduled weekly and goreleaser release-time SBOMs unaffected.
- benchmarks.yml: replace ad-hoc `go install benchstat@latest` with
  `mise exec -- benchstat` (mise.toml pins benchstat).

Todos resolved: #119, #167, #168, #171, #172, #189.

Notes:
- Mergify `dependabot-workflows` queue still only requires `Lint`
  (workflow-only changes, intentional).

Signed-off-by: UncleSp1d3r <unclesp1d3r@evilbitlabs.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking_change Significant changes that disrupt backward compatibility. dependencies Pull requests that update a dependency file go Pull requests that update go code performance Performance optimization and improvements priority:normal Normal priority issue testing Test infrastructure and test-related issues type:feature New feature implementation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Enhancement: Consider streaming generation for large configurations

1 participant